diff options
author | imarom <imarom@cisco.com> | 2015-11-11 13:48:02 +0200 |
---|---|---|
committer | imarom <imarom@cisco.com> | 2015-11-11 13:48:02 +0200 |
commit | 467382a7611f478d66cf58c1307f079239f7bac6 (patch) | |
tree | 6652a456f6e67fa462a5a2ec44bffabc9a05406a /scripts/automation/trex_control_plane/console | |
parent | a7983ed267e02a9c6a39c898c58e96b5d878e3f2 (diff) |
lightweight console
Diffstat (limited to 'scripts/automation/trex_control_plane/console')
4 files changed, 1194 insertions, 942 deletions
diff --git a/scripts/automation/trex_control_plane/console/old_console.py b/scripts/automation/trex_control_plane/console/old_console.py new file mode 100644 index 00000000..93c7e3f4 --- /dev/null +++ b/scripts/automation/trex_control_plane/console/old_console.py @@ -0,0 +1,946 @@ + +# main console object +class TRexConsole1(cmd.Cmd): + """Trex Console""" + + def __init__(self, stateless_client, verbose): + cmd.Cmd.__init__(self) + + self.stateless_client = stateless_client + + self.do_connect("") + + self.intro = "\n-=TRex Console v{ver}=-\n".format(ver=__version__) + self.intro += "\nType 'help' or '?' for supported actions\n" + + self.verbose = False + self._silent = True + + self.postcmd(False, "") + + self.user_streams = {} + self.streams_db = CStreamsDB() + + + # a cool hack - i stole this function and added space + def completenames(self, text, *ignored): + 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''' + if line == "": + print "\nverbose is " + ("on\n" if self.verbose else "off\n") + + elif line == "on": + self.verbose = True + self.stateless_client.set_verbose(True) + print green("\nverbose set to on\n") + + elif line == "off": + self.verbose = False + self.stateless_client.set_verbose(False) + print green("\nverbose set to off\n") + + else: + 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''' + + 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" + for func in msg: + if func: + print func + print '' + print format_text("[SUCCESS]\n", 'green', 'bold') + return + + def do_ping(self, line): + '''Pings the RPC server\n''' + + print "\n-> Pinging RPC server" + + res_ok, msg = self.stateless_client.ping() + if res_ok: + print format_text("[SUCCESS]\n", 'green', 'bold') + else: + print "\n*** " + msg + "\n" + return + + def do_force_acquire(self, line): + '''Acquires ports by force\n''' + + 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()} + + 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: + for port_id in line.split(' '): + 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)) + + port_list = list(port_list) + + else: + port_list = [i for i in xrange(0, self.stateless_client.get_port_count())] + + return port_list + + + def do_acquire(self, line, force=False): + '''Acquire ports\n''' + + # 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 acquire all available ports") + return + + if args[0] == "all": + 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) + + # rc, resp_list = self.stateless_client.take_ownership(port_list, force) + 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') + + + def port_auto_complete(self, text, line, begidx, endidx, acquired=True, active=False): + if acquired: + 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()) + 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''' + + # 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 = 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) + + 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 + + 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''' + + if line == "": + 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 + + res_ok, msg = self.stateless_client.connect(sp[0], sp[1]) + + if res_ok: + 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 + + # def do_rpc (self, line): + # '''Launches a RPC on the server\n''' + # + # if line == "": + # print "\nUsage: [method name] [param dict as string]\n" + # print "Example: rpc test_add {'x': 12, 'y': 17}\n" + # return + # + # sp = line.split(' ', 1) + # method = sp[0] + # + # params = None + # bad_parse = False + # if len(sp) > 1: + # + # try: + # params = ast.literal_eval(sp[1]) + # if not isinstance(params, dict): + # bad_parse = True + # + # except ValueError as e1: + # bad_parse = True + # except SyntaxError as e2: + # bad_parse = True + # + # if bad_parse: + # print "\nValue should be a valid dict: '{0}'".format(sp[1]) + # print "\nUsage: [method name] [param dict as string]\n" + # print "Example: rpc test_add {'x': 12, 'y': 17}\n" + # return + # + # res_ok, msg = self.stateless_client.transmit(method, params) + # if res_ok: + # print "\nServer Response:\n\n" + pretty_json(json.dumps(msg)) + "\n" + # else: + # print "\n*** " + msg + "\n" + # #print "Please try 'reconnect' to reconnect to server" + # + # + # def complete_rpc (self, text, line, begidx, endidx): + # return [x + # for x in self.supported_rpc + # if x.startswith(text)] + + 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) + + def do_quit(self, line): + '''Exit the client\n''' + return True + + def do_disconnect (self, line): + '''Disconnect from the server\n''' + if not self.stateless_client.is_connected(): + print "Not connected to server\n" + return + + res_ok, msg = self.stateless_client.disconnect() + if res_ok: + 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 > " + else: + self.supported_rpc = None + self.prompt = "TRex (offline) > " + + return stop + + 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_stream_db_add(self, line): + '''Loads a YAML stream list serialization into user console \n''' + args = line.split() + if len(args) >= 2: + name = args[0] + yaml_path = args[1] + try: + multiplier = args[2] + except IndexError: + multiplier = 1 + stream_list = CStreamList() + loaded_obj = stream_list.load_yaml(yaml_path, multiplier) + # 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 green("Stream pack '{0}' loaded and added successfully\n".format(name)) + else: + 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') + + return + else: + 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): + dir = os.path.dirname(text) + if dir: + path = dir + else: + path = "." + start_string = os.path.basename(text) + return [x + for x in os.listdir(path) + if x.startswith(start_string)] + + + 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]) + else: + return [text] + + 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.streams_db.get_stream_pack(list_name)#user_streams[list_name] + if len(args) >= 2 and args[1] == "full": + print pretty_json(json.dumps(stream.compiled)) + else: + print pretty_json(json.dumps(stream.loaded)) + except KeyError as e: + print "Unknown stream list name provided" + else: + 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 + for x in self.streams_db.get_loaded_streams_names() + 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) + 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 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') + + + 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): + '''Assign loaded stream pack into specified ports on TRex\n''' + 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[1] == "all": + 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(' '.join(args[1:])) + owned = set(self.stateless_client.get_acquired_ports()) + try: + if set(port_list).issubset(owned): + res_ok, log = self.stateless_client.add_stream_pack(stream_list.compiled, port_id=port_list) + # 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') + 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, " + "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)] + elif arg_num >= 2: + # return optional ports to attach to + return self.port_auto_complete(text, line, begidx, endidx) + 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 red("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 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 = 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) + + # rc, resp_list = self.stateless_client.take_ownership(port_list, force) + 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') + + def complete_remove_all_streams(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx) + + def do_start(self, line): + '''Start selected traffic in specified ports on TRex\n''' + # make sure that the user wants to acquire all + parser = parsing_opts.gen_parser("start", self.do_start.__doc__, + parsing_opts.PORT_LIST_WITH_ALL, + parsing_opts.FORCE, + parsing_opts.STREAM_FROM_PATH_OR_FILE, + parsing_opts.DURATION, + parsing_opts.MULTIPLIER) + opts = parser.parse_args(line.split()) + if opts is None: + # avoid further processing in this command + return + # print opts + port_list = self.extract_port_list(opts) + # print port_list + if opts.force: + # stop all active ports, if any + res_ok = self.stop_traffic(set(self.stateless_client.get_active_ports()).intersection(port_list)) + if not res_ok: + print yellow("[ABORTED]\n") + return + # remove all traffic from ports + res_ok = self.remove_all_streams(port_list) + if not res_ok: + print yellow("[ABORTED]\n") + return + # decide which traffic to use + stream_pack_name = None + if opts.db: + # use pre-loaded traffic + print format_text('{:<30}'.format("Load stream pack (from DB):"), 'bold'), + if opts.db not in self.streams_db.get_loaded_streams_names(): + print format_text("[FAILED]\n", 'red', 'bold') + print yellow("[ABORTED]\n") + return + else: + stream_pack_name = opts.db + else: + # try loading a YAML file + print format_text('{:<30}'.format("Load stream pack (from file):"), 'bold'), + stream_list = CStreamList() + loaded_obj = stream_list.load_yaml(opts.file[0]) + # print self.stateless_client.pretty_json(json.dumps(loaded_obj)) + try: + compiled_streams = stream_list.compile_streams() + res_ok = self.streams_db.load_streams(opts.file[1], + LoadedStreamList(loaded_obj, + [StreamPack(v.stream_id, v.stream.dump()) + for k, v in compiled_streams.items()])) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + print yellow("[ABORTED]\n") + return + print format_text("[SUCCESS]\n", 'green', 'bold') + stream_pack_name = opts.file[1] + except Exception as e: + print format_text("[FAILED]\n", 'red', 'bold') + print yellow("[ABORTED]\n") + res_ok = self.attach_to_port(stream_pack_name, port_list) + if not res_ok: + print yellow("[ABORTED]\n") + return + # finally, start the traffic + res_ok = self.start_traffic(opts.mult, port_list) + if not res_ok: + print yellow("[ABORTED]\n") + return + return + + def help_start(self): + self.do_start("-h") + + def do_stop(self, line): + '''Stop active traffic in specified ports on TRex\n''' + parser = parsing_opts.gen_parser("stop", self.do_stop.__doc__, + parsing_opts.PORT_LIST_WITH_ALL) + opts = parser.parse_args(line.split()) + if opts is None: + # avoid further processing in this command + return + port_list = self.extract_port_list(opts) + res_ok = self.stop_traffic(port_list) + return + + + def help_stop(self): + self.do_stop("-h") + + + def do_debug(self, line): + '''Enter DEBUG mode of the console to invoke smaller building blocks with server''' + i = DebugTRexConsole(self) + i.prompt = self.prompt[:-3] + ':' + blue('debug') + ' > ' + i.cmdloop() + + # aliasing + do_exit = do_EOF = do_q = do_quit + + # ----- utility methods ----- # + + def start_traffic(self, multiplier, port_list):#, silent=True): + print format_text('{:<30}'.format("Start traffic:"), 'bold'), + try: + res_ok, log = self.stateless_client.start_traffic(multiplier, port_id=port_list) + if not self._silent: + print '' + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return False + print format_text("[SUCCESS]\n", 'green', 'bold') + return True + except ValueError as e: + print '' + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + return False + + def attach_to_port(self, stream_pack_name, port_list): + print format_text('{:<30}'.format("Attaching traffic to ports:"), 'bold'), + 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 + try: + res_ok, log = self.stateless_client.add_stream_pack(stream_list.compiled, port_id=port_list) + if not self._silent: + print '' + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return False + print format_text("[SUCCESS]\n", 'green', 'bold') + return True + except ValueError as e: + print '' + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + return False + + def stop_traffic(self, port_list): + print format_text('{:<30}'.format("Stop traffic:"), 'bold'), + try: + res_ok, log = self.stateless_client.stop_traffic(port_id=port_list) + if not self._silent: + print '' + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + return True + except ValueError as e: + print '' + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + + def remove_all_streams(self, port_list): + '''Remove all streams from given port_list''' + print format_text('{:<30}'.format("Remove all streams:"), 'bold'), + try: + res_ok, log = self.stateless_client.remove_all_streams(port_id=port_list) + if not self._silent: + print '' + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + return True + except ValueError as e: + print '' + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + + + + + + def extract_port_list(self, opts): + if opts.all_ports or "all" in opts.ports: + # handling all ports + port_list = self.stateless_client.get_acquired_ports() + else: + port_list = self.extract_port_ids_from_list(opts.ports) + return port_list + + def decode_multiplier(self, opts_mult): + pass + + +class DebugTRexConsole(cmd.Cmd): + + def __init__(self, trex_main_console): + cmd.Cmd.__init__(self) + self.trex_console = trex_main_console + self.stateless_client = self.trex_console.stateless_client + self.streams_db = self.trex_console.streams_db + self.register_main_console_methods() + self.do_silent("on") + pass + + # ----- super methods overriding ----- # + def completenames(self, text, *ignored): + dotext = 'do_'+text + return [a[3:]+' ' for a in self.get_names() if a.startswith(dotext)] + + def get_names(self): + result = cmd.Cmd.get_names(self) + result += self.trex_console.get_names() + return list(set(result)) + + def register_main_console_methods(self): + main_names = set(self.trex_console.get_names()).difference(set(dir(self.__class__))) + for name in main_names: + for prefix in 'do_', 'help_', 'complete_': + if name.startswith(prefix): + self.__dict__[name] = getattr(self.trex_console, name) + + # if (name[:3] == 'do_') or (name[:5] == 'help_') or (name[:9] == 'complete_'): + # chosen.append(name) + # self.__dict__[name] = getattr(self.trex_console, name) + # # setattr(self, name, classmethod(getattr(self.trex_console, name))) + + # print chosen + # self.get_names() + + # return result + + + # ----- DEBUGGING methods ----- # + # set silent on / off + def do_silent(self, line): + '''Shows or set silent mode\n''' + if line == "": + print "\nsilent mode is " + ("on\n" if self.trex_console._silent else "off\n") + + elif line == "on": + self.verbose = True + self.stateless_client.set_verbose(True) + print green("\nsilent set to on\n") + + elif line == "off": + self.verbose = False + self.stateless_client.set_verbose(False) + print green("\nsilent set to off\n") + + else: + print magenta("\nplease specify 'on' or 'off'\n") + + def do_quit(self, line): + '''Exit the debug client back to main console\n''' + self.do_silent("off") + return True + + 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 + if opts is None: + # avoid further processing in this command + return + try: + port_list = self.trex_console.extract_port_list(opts) + return self.trex_console.start_traffic(opts.mult, port_list) + except Exception as e: + print e + return + + def do_stop_traffic(self, line): + '''Stop active traffic in specified ports on TRex\n''' + parser = parsing_opts.gen_parser("stop_traffic", self.do_stop_traffic.__doc__, + parsing_opts.PORT_LIST_WITH_ALL) + opts = parser.parse_args(line.split()) + # print opts + # return + if opts is None: + # avoid further processing in this command + return + try: + port_list = self.trex_console.extract_port_list(opts) + return self.trex_console.stop_traffic(port_list) + except Exception as e: + print e + return + + + def complete_stop_traffic(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx, active=True) + + # 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 + # + + + return + 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(1.0, port_id=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) + return [text] + + def help_start_traffic(self): + self.do_start_traffic("-h") + + def help_stop_traffic(self): + self.do_stop_traffic("-h") + + # def do_help(self): + + def do_rpc (self, line): + '''Launches a RPC on the server\n''' + + if line == "": + print "\nUsage: [method name] [param dict as string]\n" + print "Example: rpc test_add {'x': 12, 'y': 17}\n" + return + + sp = line.split(' ', 1) + method = sp[0] + + params = None + bad_parse = False + if len(sp) > 1: + + try: + params = ast.literal_eval(sp[1]) + if not isinstance(params, dict): + bad_parse = True + + except ValueError as e1: + bad_parse = True + except SyntaxError as e2: + bad_parse = True + + if bad_parse: + print "\nValue should be a valid dict: '{0}'".format(sp[1]) + print "\nUsage: [method name] [param dict as string]\n" + print "Example: rpc test_add {'x': 12, 'y': 17}\n" + return + + res_ok, msg = self.stateless_client.transmit(method, params) + if res_ok: + print "\nServer Response:\n\n" + pretty_json(json.dumps(msg)) + "\n" + else: + print "\n*** " + msg + "\n" + #print "Please try 'reconnect' to reconnect to server" + + + def complete_rpc (self, text, line, begidx, endidx): + return [x + for x in self.trex_console.supported_rpc + if x.startswith(text)] + + # aliasing + do_exit = do_EOF = do_q = do_quit + +# diff --git a/scripts/automation/trex_control_plane/console/parsing_opts.py b/scripts/automation/trex_control_plane/console/parsing_opts.py index e701b7db..f983d837 100755 --- a/scripts/automation/trex_control_plane/console/parsing_opts.py +++ b/scripts/automation/trex_control_plane/console/parsing_opts.py @@ -2,6 +2,7 @@ import argparse from collections import namedtuple import sys import re +import os ArgumentPack = namedtuple('ArgumentPack', ['name_or_flags', 'options']) ArgumentGroup = namedtuple('ArgumentGroup', ['type', 'args', 'options']) @@ -14,9 +15,10 @@ ALL_PORTS = 3 PORT_LIST_WITH_ALL = 4 FILE_PATH = 5 FILE_FROM_DB = 6 -STREAM_FROM_PATH_OR_FILE = 7 -DURATION = 8 -FORCE = 9 +SERVER_IP = 7 +STREAM_FROM_PATH_OR_FILE = 8 +DURATION = 9 +FORCE = 10 # list of ArgumentGroup types MUTEX = 1 @@ -61,20 +63,27 @@ def match_multiplier(val): +def is_valid_file(filename): + if not os.path.isfile(filename): + raise argparse.ArgumentTypeError("The file '%s' does not exist" % filename) + + return filename + OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], {'help': "Set multiplier for stream", 'dest': "mult", 'default': 1.0, 'type': match_multiplier}), + PORT_LIST: ArgumentPack(['--port'], {"nargs": '+', - # "action": "store_" 'dest':'ports', 'metavar': 'PORTS', - # 'type': int, + 'type': int, 'help': "A list of ports on which to apply the command", 'default': []}), + ALL_PORTS: ArgumentPack(['-a'], {"action": "store_true", "dest": "all_ports", @@ -88,15 +97,22 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], {"action": "store_true", 'default': False, 'help': "Set if you want to stop active ports before applying new TRex run on them."}), + FILE_PATH: ArgumentPack(['-f'], - {'metavar': ('FILE', 'DB_NAME'), + {'metavar': 'FILE', 'dest': 'file', - 'nargs': 2, - 'help': "File path to YAML file that describes a stream pack. " - "Second argument is a name to store the loaded yaml file into db."}), + 'nargs': 1, + 'type': is_valid_file, + 'help': "File path to YAML file that describes a stream pack. "}), + FILE_FROM_DB: ArgumentPack(['--db'], {'metavar': 'LOADED_STREAM_PACK', 'help': "A stream pack which already loaded into console cache."}), + + SERVER_IP: ArgumentPack(['--server'], + {'metavar': 'SERVER', + 'help': "server IP"}), + # advanced options PORT_LIST_WITH_ALL: ArgumentGroup(MUTEX, [PORT_LIST, ALL_PORTS], @@ -109,33 +125,44 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], class CCmdArgParser(argparse.ArgumentParser): - def __init__(self, *args, **kwargs): + def __init__(self, stateless_client, *args, **kwargs): super(CCmdArgParser, self).__init__(*args, **kwargs) - - # def exit(self, status=0, message=None): - # try: - # return super(CCmdArgParser, self).exit(status, message) # this will trigger system exit! - # except SystemExit: - # print "Caught system exit!!" - # return -1 - # # return + self.stateless_client = stateless_client def parse_args(self, args=None, namespace=None): try: - return super(CCmdArgParser, self).parse_args(args, namespace) + opts = super(CCmdArgParser, self).parse_args(args, namespace) + if opts is None: + return None + + if opts.all_ports: + opts.ports = self.stateless_client.get_port_ids() + + for port in opts.ports: + if not self.stateless_client._is_ports_valid(port): + self.error("port id {0} is not a valid\n".format(port)) + + return opts + except SystemExit: # recover from system exit scenarios, such as "help", or bad arguments. return None +def get_flags (opt): + return OPTIONS_DB[opt].name_or_flags -def gen_parser(op_name, description, *args): - parser = CCmdArgParser(prog=op_name, conflict_handler='resolve', - # add_help=False, +def gen_parser(stateless_client, op_name, description, *args): + parser = CCmdArgParser(stateless_client, prog=op_name, conflict_handler='resolve', description=description) for param in args: try: - argument = OPTIONS_DB[param] + + if isinstance(param, int): + argument = OPTIONS_DB[param] + else: + argument = param + if isinstance(argument, ArgumentGroup): if argument.type == MUTEX: # handle as mutually exclusive group @@ -157,5 +184,6 @@ def gen_parser(op_name, description, *args): 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 a61881a1..06ae762a 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -30,6 +30,7 @@ import tty, termios import trex_root_path from common.trex_streams import * from client.trex_stateless_client import CTRexStatelessClient +from client.trex_stateless_client import RpcResponseStatus from common.text_opts import * from client_utils.general_utils import user_input, get_current_user import parsing_opts @@ -40,43 +41,32 @@ __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) - - 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): self.stream_packs = {} + def load_yaml_file (self, filename): + + stream_pack_name = filename + if stream_pack_name in self.get_loaded_streams_names(): + self.remove_stream_packs(stream_pack_name) + + stream_list = CStreamList() + loaded_obj = stream_list.load_yaml(filename) + + try: + compiled_streams = stream_list.compile_streams() + rc = self.load_streams(stream_pack_name, + LoadedStreamList(loaded_obj, + [StreamPack(v.stream_id, v.stream.dump()) + for k, v in compiled_streams.items()])) + + except Exception as e: + return None + + return self.get_stream_pack(stream_pack_name) + def load_streams(self, name, LoadedStreamList_obj): if name in self.stream_packs: return False @@ -98,84 +88,79 @@ class CStreamsDB(object): 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 -class CmdMenu(object): - def __init__ (self): - self.menus = [] - - - def add_menu (self, caption, options): - menu = {} - menu['caption'] = caption - menu['options'] = options - self.menus.append(menu) - - def show (self): - cur_level = 0 - print "\n" - - selected_path = [] - for menu in self.menus: - # show all the options - print "{0}\n".format(menu['caption']) - for i, option in enumerate(menu['options']): - print "{0}. {1}".format(i + 1, option) - - #print "\nPlease select an option: " - - choices = range(0, len(menu['options'])) - choices = [ chr(x + 48) for x in choices] - - print "" - ch = readch(choices) - print "" - - if ch == None: - return None - - selected_path.append(int(ch) - 1) - - return selected_path + def stream_pack_exists (self, name): + return name in self.get_loaded_streams_names() + def get_stream_pack(self, name): + if not self.stream_pack_exists(name): + return None + else: + return self.stream_packs.get(name) -class AddStreamMenu(CmdMenu): - def __init__ (self): - super(AddStreamMenu, self).__init__() - self.add_menu('Please select type of stream', ['a', 'b', 'c']) - self.add_menu('Please select ISG', ['d', 'e', 'f']) +# # main console object class TRexConsole(cmd.Cmd): """Trex Console""" - def __init__(self, stateless_client, verbose): + def __init__(self, stateless_client, acquire_all_ports = True, verbose = False): cmd.Cmd.__init__(self) self.stateless_client = stateless_client + self.verbose = verbose + self.acquire_all_ports = acquire_all_ports + self.do_connect("") self.intro = "\n-=TRex Console v{ver}=-\n".format(ver=__version__) self.intro += "\nType 'help' or '?' for supported actions\n" - self.verbose = False - self._silent = True - self.postcmd(False, "") - self.user_streams = {} self.streams_db = CStreamsDB() + ################### internal section ######################## + # a cool hack - i stole this function and added space def completenames(self, text, *ignored): dotext = 'do_'+text return [a[3:]+' ' for a in self.get_names() if a.startswith(dotext)] + + def register_main_console_methods(self): + main_names = set(self.trex_console.get_names()).difference(set(dir(self.__class__))) + for name in main_names: + for prefix in 'do_', 'help_', 'complete_': + if name.startswith(prefix): + self.__dict__[name] = getattr(self.trex_console, name) + + def postcmd(self, stop, line): + if self.stateless_client.is_connected(): + self.prompt = "TRex > " + else: + self.supported_rpc = None + self.prompt = "TRex (offline) > " + + return stop + + def default(self, line): + print "'{0}' is an unrecognized command. type 'help' or '?' for a list\n".format(line) + + @staticmethod + def tree_autocomplete(text): + dir = os.path.dirname(text) + if dir: + path = dir + else: + path = "." + start_string = os.path.basename(text) + return [x + for x in os.listdir(path) + if x.startswith(start_string)] + + ####################### shell commands ####################### # set verbose on / off def do_verbose(self, line): @@ -196,169 +181,11 @@ class TRexConsole(cmd.Cmd): else: 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''' - - 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" - for func in msg: - if func: - print func - print '' - print format_text("[SUCCESS]\n", 'green', 'bold') - return - - def do_ping(self, line): - '''Pings the RPC server\n''' - - print "\n-> Pinging RPC server" - - res_ok, msg = self.stateless_client.ping() - if res_ok: - print format_text("[SUCCESS]\n", 'green', 'bold') - else: - print "\n*** " + msg + "\n" - return - - def do_force_acquire(self, line): - '''Acquires ports by force\n''' - - 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()} - - 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: - for port_id in line.split(' '): - 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)) - - port_list = list(port_list) - - else: - port_list = [i for i in xrange(0, self.stateless_client.get_port_count())] - - return port_list - - - def do_acquire(self, line, force=False): - '''Acquire ports\n''' - - # 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 acquire all available ports") - return - - if args[0] == "all": - 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) - - # rc, resp_list = self.stateless_client.take_ownership(port_list, force) - 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') - - - def port_auto_complete(self, text, line, begidx, endidx, acquired=True, active=False): - if acquired: - 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()) - 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''' - - # 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 = 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) - - 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 - - def complete_release(self, text, line, begidx, endidx): - return self.port_auto_complete(text, line, begidx, endidx) - + ############### connect def do_connect (self, line): '''Connects to the server\n''' - if line == "": - 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 - - res_ok, msg = self.stateless_client.connect(sp[0], sp[1]) - + res_ok, msg = self.stateless_client.connect() if res_ok: print format_text("[SUCCESS]\n", 'green', 'bold') else: @@ -368,730 +195,175 @@ class TRexConsole(cmd.Cmd): self.supported_rpc = self.stateless_client.get_supported_cmds().data - # def do_rpc (self, line): - # '''Launches a RPC on the server\n''' - # - # if line == "": - # print "\nUsage: [method name] [param dict as string]\n" - # print "Example: rpc test_add {'x': 12, 'y': 17}\n" - # return - # - # sp = line.split(' ', 1) - # method = sp[0] - # - # params = None - # bad_parse = False - # if len(sp) > 1: - # - # try: - # params = ast.literal_eval(sp[1]) - # if not isinstance(params, dict): - # bad_parse = True - # - # except ValueError as e1: - # bad_parse = True - # except SyntaxError as e2: - # bad_parse = True - # - # if bad_parse: - # print "\nValue should be a valid dict: '{0}'".format(sp[1]) - # print "\nUsage: [method name] [param dict as string]\n" - # print "Example: rpc test_add {'x': 12, 'y': 17}\n" - # return - # - # res_ok, msg = self.stateless_client.transmit(method, params) - # if res_ok: - # print "\nServer Response:\n\n" + pretty_json(json.dumps(msg)) + "\n" - # else: - # print "\n*** " + msg + "\n" - # #print "Please try 'reconnect' to reconnect to server" - # - # - # def complete_rpc (self, text, line, begidx, endidx): - # return [x - # for x in self.supported_rpc - # if x.startswith(text)] - - 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) - - def do_quit(self, line): - '''Exit the client\n''' - return True + if self.acquire_all_ports: + res_ok, log = self.stateless_client.acquire(self.stateless_client.get_port_ids()) + if not res_ok: + print "\n*** Failed to acquire all ports... exiting...""" - def do_disconnect (self, line): - '''Disconnect from the server\n''' - if not self.stateless_client.is_connected(): - print "Not connected to server\n" + @staticmethod + def annotate (desc, rc = None, err_log = None, ext_err_msg = None): + print format_text('\n{:<40}'.format(desc), 'bold'), + if rc == None: + print "\n" return - res_ok, msg = self.stateless_client.disconnect() - if res_ok: - 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 > " - else: - self.supported_rpc = None - self.prompt = "TRex (offline) > " - - return stop - - def default(self, line): - print "'{0}' is an unrecognized command. type 'help' or '?' for a list\n".format(line) + if rc == False: + # do we have a complex log object ? + if isinstance(err_log, list): + print "" + for func in err_log: + if func: + print func + print "" - # 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''' - args = line.split() - if len(args) >= 2: - name = args[0] - yaml_path = args[1] - try: - multiplier = args[2] - except IndexError: - multiplier = 1 - stream_list = CStreamList() - loaded_obj = stream_list.load_yaml(yaml_path, multiplier) - # 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 green("Stream pack '{0}' loaded and added successfully\n".format(name)) - else: - 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') - - return - else: - 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): - dir = os.path.dirname(text) - if dir: - path = dir - else: - path = "." - start_string = os.path.basename(text) - return [x - for x in os.listdir(path) - if x.startswith(start_string)] + elif isinstance(err_log, str): + print "\n" + err_log + "\n" + print format_text("[FAILED]\n", 'red', 'bold') + if ext_err_msg: + print format_text(ext_err_msg + "\n", 'blue', 'bold') - 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]) - else: - return [text] - - 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.streams_db.get_stream_pack(list_name)#user_streams[list_name] - if len(args) >= 2 and args[1] == "full": - print pretty_json(json.dumps(stream.compiled)) - else: - print pretty_json(json.dumps(stream.loaded)) - except KeyError as e: - print "Unknown stream list name provided" - else: - print "Available stream packs:\n{0}".format(', '.join(sorted(self.streams_db.get_loaded_streams_names()))) + return False - def complete_stream_db_show(self, text, line, begidx, endidx): - return [x - for x in self.streams_db.get_loaded_streams_names() - 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) - 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 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') + print format_text("[SUCCESS]\n", 'green', 'bold') + return True - 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): - '''Assign loaded stream pack into specified ports on TRex\n''' - 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[1] == "all": - 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(' '.join(args[1:])) - owned = set(self.stateless_client.get_acquired_ports()) - try: - if set(port_list).issubset(owned): - res_ok, log = self.stateless_client.add_stream_pack(stream_list.compiled, port_id=port_list) - # 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') - 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, " - "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)] - elif arg_num >= 2: - # return optional ports to attach to - return self.port_auto_complete(text, line, begidx, endidx) - 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 red("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 + ############### start - def do_remove_all_streams(self, line): - '''Acquire ports\n''' + def complete_start(self, text, line, begidx, endidx): + s = line.split() + l = len(s) - # 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 remove from all acquired ports") - return - if args[0] == "all": - 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) + file_flags = parsing_opts.get_flags(parsing_opts.FILE_PATH) - # rc, resp_list = self.stateless_client.take_ownership(port_list, force) - 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') + if (l > 1) and (s[l - 1] in file_flags): + return TRexConsole.tree_autocomplete("") - def complete_remove_all_streams(self, text, line, begidx, endidx): - return self.port_auto_complete(text, line, begidx, endidx) + if (l > 2) and (s[l - 2] in file_flags): + return TRexConsole.tree_autocomplete(s[l - 1]) def do_start(self, line): '''Start selected traffic in specified ports on TRex\n''' + # make sure that the user wants to acquire all - parser = parsing_opts.gen_parser("start", self.do_start.__doc__, + parser = parsing_opts.gen_parser(self.stateless_client, + "start", + self.do_start.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.FORCE, parsing_opts.STREAM_FROM_PATH_OR_FILE, parsing_opts.DURATION, parsing_opts.MULTIPLIER) + opts = parser.parse_args(line.split()) + if opts is None: - # avoid further processing in this command - return - # print opts - port_list = self.extract_port_list(opts) - # print port_list - if opts.force: - # stop all active ports, if any - res_ok = self.stop_traffic(set(self.stateless_client.get_active_ports()).intersection(port_list)) - if not res_ok: - print yellow("[ABORTED]\n") - return - # remove all traffic from ports - res_ok = self.remove_all_streams(port_list) - if not res_ok: - print yellow("[ABORTED]\n") return - # decide which traffic to use - stream_pack_name = None + if opts.db: - # use pre-loaded traffic - print format_text('{:<30}'.format("Load stream pack (from DB):"), 'bold'), - if opts.db not in self.streams_db.get_loaded_streams_names(): - print format_text("[FAILED]\n", 'red', 'bold') - print yellow("[ABORTED]\n") + stream_list = self.stream_db.get_stream_pack(opts.db) + self.annotate("Load stream pack (from DB):", (stream_list != None)) + if stream_list == None: return - else: - stream_pack_name = opts.db + else: - # try loading a YAML file - print format_text('{:<30}'.format("Load stream pack (from file):"), 'bold'), - stream_list = CStreamList() - loaded_obj = stream_list.load_yaml(opts.file[0]) - # print self.stateless_client.pretty_json(json.dumps(loaded_obj)) - try: - compiled_streams = stream_list.compile_streams() - res_ok = self.streams_db.load_streams(opts.file[1], - LoadedStreamList(loaded_obj, - [StreamPack(v.stream_id, v.stream.dump()) - for k, v in compiled_streams.items()])) - if not res_ok: - print format_text("[FAILED]\n", 'red', 'bold') - print yellow("[ABORTED]\n") - return - print format_text("[SUCCESS]\n", 'green', 'bold') - stream_pack_name = opts.file[1] - except Exception as e: - print format_text("[FAILED]\n", 'red', 'bold') - print yellow("[ABORTED]\n") - res_ok = self.attach_to_port(stream_pack_name, port_list) - if not res_ok: - print yellow("[ABORTED]\n") - return - # finally, start the traffic - res_ok = self.start_traffic(opts.mult, port_list) - if not res_ok: - print yellow("[ABORTED]\n") - return + # load streams from file + stream_list = self.streams_db.load_yaml_file(opts.file[0]) + self.annotate("Load stream pack (from file):", (stream_list != None)) + if stream_list == None: + return + + + self.stateless_client.cmd_start(opts.ports, stream_list, opts.mult, opts.force, self.annotate) return + def help_start(self): self.do_start("-h") + ############# stop def do_stop(self, line): '''Stop active traffic in specified ports on TRex\n''' - parser = parsing_opts.gen_parser("stop", self.do_stop.__doc__, + parser = parsing_opts.gen_parser(self.stateless_client, + "stop", + self.do_stop.__doc__, parsing_opts.PORT_LIST_WITH_ALL) + opts = parser.parse_args(line.split()) if opts is None: - # avoid further processing in this command return - port_list = self.extract_port_list(opts) - res_ok = self.stop_traffic(port_list) - return + self.stateless_client.cmd_stop(opts.ports, self.annotate) + return def help_stop(self): self.do_stop("-h") + ########## reset + def do_reset (self, line): + '''force stop all ports\n''' + self.stateless_client.cmd_reset(self.annotate) - def do_debug(self, line): - '''Enter DEBUG mode of the console to invoke smaller building blocks with server''' - i = DebugTRexConsole(self) - i.prompt = self.prompt[:-3] + ':' + blue('debug') + ' > ' - i.cmdloop() - - # aliasing - do_exit = do_EOF = do_q = do_quit - - # ----- utility methods ----- # - - def start_traffic(self, multiplier, port_list):#, silent=True): - print format_text('{:<30}'.format("Start traffic:"), 'bold'), - try: - res_ok, log = self.stateless_client.start_traffic(multiplier, port_id=port_list) - if not self._silent: - print '' - self.prompt_response(log) - if not res_ok: - print format_text("[FAILED]\n", 'red', 'bold') - return False - print format_text("[SUCCESS]\n", 'green', 'bold') - return True - except ValueError as e: - print '' - print magenta(str(e)) - print format_text("[FAILED]\n", 'red', 'bold') - return False + + # tui + def do_tui (self, line): + '''Shows a graphical console\n''' - def attach_to_port(self, stream_pack_name, port_list): - print format_text('{:<30}'.format("Attaching traffic to ports:"), 'bold'), - 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') + if not self.stateless_client.is_connected(): + print "Not connected to server\n" return - try: - res_ok, log = self.stateless_client.add_stream_pack(stream_list.compiled, port_id=port_list) - if not self._silent: - print '' - self.prompt_response(log) - if not res_ok: - print format_text("[FAILED]\n", 'red', 'bold') - return False - print format_text("[SUCCESS]\n", 'green', 'bold') - return True - except ValueError as e: - print '' - print magenta(str(e)) - print format_text("[FAILED]\n", 'red', 'bold') - return False - - def stop_traffic(self, port_list): - print format_text('{:<30}'.format("Stop traffic:"), 'bold'), - try: - res_ok, log = self.stateless_client.stop_traffic(port_id=port_list) - if not self._silent: - print '' - self.prompt_response(log) - if not res_ok: - print format_text("[FAILED]\n", 'red', 'bold') - return - print format_text("[SUCCESS]\n", 'green', 'bold') - return True - except ValueError as e: - print '' - print magenta(str(e)) - print format_text("[FAILED]\n", 'red', 'bold') - - def remove_all_streams(self, port_list): - '''Remove all streams from given port_list''' - print format_text('{:<30}'.format("Remove all streams:"), 'bold'), - try: - res_ok, log = self.stateless_client.remove_all_streams(port_id=port_list) - if not self._silent: - print '' - self.prompt_response(log) - if not res_ok: - print format_text("[FAILED]\n", 'red', 'bold') - return - print format_text("[SUCCESS]\n", 'green', 'bold') - return True - except ValueError as e: - print '' - print magenta(str(e)) - print format_text("[FAILED]\n", 'red', 'bold') - - - - - - def extract_port_list(self, opts): - if opts.all_ports or "all" in opts.ports: - # handling all ports - port_list = self.stateless_client.get_acquired_ports() - else: - port_list = self.extract_port_ids_from_list(opts.ports) - return port_list - - def decode_multiplier(self, opts_mult): - pass - - -class DebugTRexConsole(cmd.Cmd): - - def __init__(self, trex_main_console): - cmd.Cmd.__init__(self) - self.trex_console = trex_main_console - self.stateless_client = self.trex_console.stateless_client - self.streams_db = self.trex_console.streams_db - self.register_main_console_methods() - self.do_silent("on") - pass - - # ----- super methods overriding ----- # - def completenames(self, text, *ignored): - dotext = 'do_'+text - return [a[3:]+' ' for a in self.get_names() if a.startswith(dotext)] - def get_names(self): - result = cmd.Cmd.get_names(self) - result += self.trex_console.get_names() - return list(set(result)) - - def register_main_console_methods(self): - main_names = set(self.trex_console.get_names()).difference(set(dir(self.__class__))) - for name in main_names: - for prefix in 'do_', 'help_', 'complete_': - if name.startswith(prefix): - self.__dict__[name] = getattr(self.trex_console, name) - - # if (name[:3] == 'do_') or (name[:5] == 'help_') or (name[:9] == 'complete_'): - # chosen.append(name) - # self.__dict__[name] = getattr(self.trex_console, name) - # # setattr(self, name, classmethod(getattr(self.trex_console, name))) - - # print chosen - # self.get_names() - - # return result - - - # ----- DEBUGGING methods ----- # - # set silent on / off - def do_silent(self, line): - '''Shows or set silent mode\n''' - if line == "": - print "\nsilent mode is " + ("on\n" if self.trex_console._silent else "off\n") - - elif line == "on": - self.verbose = True - self.stateless_client.set_verbose(True) - print green("\nsilent set to on\n") - - elif line == "off": - self.verbose = False - self.stateless_client.set_verbose(False) - print green("\nsilent set to off\n") - - else: - print magenta("\nplease specify 'on' or 'off'\n") + self.do_verbose('off') + trex_status.show_trex_status(self.stateless_client) + # quit function def do_quit(self, line): - '''Exit the debug client back to main console\n''' - self.do_silent("off") + '''Exit the client\n''' return True - 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 - if opts is None: - # avoid further processing in this command - return - try: - port_list = self.trex_console.extract_port_list(opts) - return self.trex_console.start_traffic(opts.mult, port_list) - except Exception as e: - print e - return - - def do_stop_traffic(self, line): - '''Stop active traffic in specified ports on TRex\n''' - parser = parsing_opts.gen_parser("stop_traffic", self.do_stop_traffic.__doc__, - parsing_opts.PORT_LIST_WITH_ALL) - opts = parser.parse_args(line.split()) - # print opts - # return - if opts is None: - # avoid further processing in this command - return - try: - port_list = self.trex_console.extract_port_list(opts) - return self.trex_console.stop_traffic(port_list) - except Exception as e: - print e - return - - - def complete_stop_traffic(self, text, line, begidx, endidx): - return self.port_auto_complete(text, line, begidx, endidx, active=True) - - # 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 - # - - - return - 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(1.0, port_id=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) - return [text] - - def help_start_traffic(self): - self.do_start_traffic("-h") - - def help_stop_traffic(self): - self.do_stop_traffic("-h") - - # def do_help(self): - - def do_rpc (self, line): - '''Launches a RPC on the server\n''' + + 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") or (cmd == "q") or (cmd == "exit")): + 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) - if line == "": - print "\nUsage: [method name] [param dict as string]\n" - print "Example: rpc test_add {'x': 12, 'y': 17}\n" - return - - sp = line.split(' ', 1) - method = sp[0] - - params = None - bad_parse = False - if len(sp) > 1: - - try: - params = ast.literal_eval(sp[1]) - if not isinstance(params, dict): - bad_parse = True - - except ValueError as e1: - bad_parse = True - except SyntaxError as e2: - bad_parse = True - - if bad_parse: - print "\nValue should be a valid dict: '{0}'".format(sp[1]) - print "\nUsage: [method name] [param dict as string]\n" - print "Example: rpc test_add {'x': 12, 'y': 17}\n" - return - - res_ok, msg = self.stateless_client.transmit(method, params) - if res_ok: - print "\nServer Response:\n\n" + pretty_json(json.dumps(msg)) + "\n" - else: - print "\n*** " + msg + "\n" - #print "Please try 'reconnect' to reconnect to server" - - - def complete_rpc (self, text, line, begidx, endidx): - return [x - for x in self.trex_console.supported_rpc - if x.startswith(text)] - - # aliasing do_exit = do_EOF = do_q = do_quit + def setParserOptions(): parser = argparse.ArgumentParser(prog="trex_console.py") @@ -1099,12 +371,12 @@ def setParserOptions(): default = "localhost", type = str) - parser.add_argument("-p", "--port", help = "TRex Server Port [default is 4505]\n", - default = 4505, + parser.add_argument("-p", "--port", help = "TRex Server Port [default is 5505]\n", + default = 5505, type = int) - parser.add_argument("--async_port", help = "TRex ASync Publisher Port [default is 4506]\n", - default = 4506, + parser.add_argument("--async_port", help = "TRex ASync Publisher Port [default is 4505]\n", + default = 4505, dest='pub', type = int) @@ -1116,6 +388,11 @@ def setParserOptions(): action="store_true", help="Switch ON verbose option. Default is: OFF.", default = False) + + parser.add_argument("--no_acquire", dest="acquire", + action="store_false", help="Acquire all ports on connect. Default is: ON.", + default = True) + return parser @@ -1128,7 +405,7 @@ def main(): # console try: - console = TRexConsole(stateless_client, options.verbose) + console = TRexConsole(stateless_client, options.acquire, options.verbose) console.cmdloop() except KeyboardInterrupt as e: print "\n\n*** Caught Ctrl + C... Exiting...\n\n" diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py index 2b97d7d3..a54b718e 100644 --- a/scripts/automation/trex_control_plane/console/trex_status.py +++ b/scripts/automation/trex_control_plane/console/trex_status.py @@ -168,7 +168,8 @@ class PortsStatsPanel(TrexStatusPanel): port_stats.get_rel("ibytes", format = True, suffix = "B")))) else: - self.getwin().addstr(5 + (i * 4), 2, 2, "{:^15} {:^30} {:^30} {:^30}".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"]), "N/A", "N/A", @@ -284,7 +285,7 @@ class SinglePortPanel(TrexStatusPanel): port_stats.get_rel("ibytes", format = True, suffix = "B")))) else: - self.getwin().addstr(y + (i * 4), 2, 2, "{:^15} {:^30} {:^30} {:^30}".format( + 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"]), "N/A", "N/A", |