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 1.2.3-korg From ebb0b48faca96bad7bfe8da0bf80df7c7c80350d Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Sun, 25 Oct 2015 11:33:48 +0200 Subject: HLTAPI progress... --- .../trex_control_plane/client/trex_hltapi.py | 30 ++++++++++++++++++++-- .../client/trex_stateless_client.py | 5 ++++ .../client_utils/jsonrpc_client.py | 4 +-- .../trex_control_plane/console/trex_console.py | 3 ++- 4 files changed, 37 insertions(+), 5 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/client/trex_hltapi.py b/scripts/automation/trex_control_plane/client/trex_hltapi.py index b180eb5b..7453d8ec 100755 --- a/scripts/automation/trex_control_plane/client/trex_hltapi.py +++ b/scripts/automation/trex_control_plane/client/trex_hltapi.py @@ -11,14 +11,40 @@ class CTRexHltApi(object): def __init__(self): pass - def connect_status(self): + def connect(self, device, port_list, username, reset=False, break_locks=False): pass + def interface_config(self, port_handle, mode="config"): + pass + + def get_status(self): + pass + + def get_port_handler(self): + pass + + def traffic_config(self, mode, port_handle, + mac_src, mac_dst, + l3_protocol, ip_src_addr, ip_dst_addr, l3_length, + transmit_mode, rate_pps): + pass + def traffic_control(self, action, port_handle): + pass - def config_traffic(self): + def traffic_stats(self, port_handle, mode): pass + def get_aggregate_port_stats(self, port_handle): + return self.traffic_stats(port_handle, mode="aggregate") + + def get_stream_stats(self, port_handle): + return self.traffic_stats(port_handle, mode="stream") + + + + + if __name__ == "__main__": pass diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py index 8956aaf5..7d287a5e 100755 --- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py @@ -63,6 +63,9 @@ class CTRexStatelessClient(object): return self._system_info # ----- user-access methods ----- # + def connect(self): + self.tx_link.connect() + def ping(self): return self.transmit("ping") @@ -323,6 +326,8 @@ class CTRexStatelessClient(object): self.server = server self.port = port self.rpc_link = JsonRpcClient(self.server, self.port) + + def connect(self): if not self.virtual: self.rpc_link.connect() diff --git a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py index ed14e6f8..1c5dbe7e 100755 --- a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py +++ b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py @@ -182,7 +182,7 @@ class JsonRpcClient(object): # if no error there should be a result if ("result" not in response_json): - return False, "Malfromed Response ({0})".format(str(response)) + return False, "Malformed Response ({0})".format(str(response)) return True, response_json["result"] @@ -200,7 +200,7 @@ class JsonRpcClient(object): else: return False, "Not connected to server" - def connect(self, server = None, port = None): + def connect(self, server=None, port=None): if self.connected: self.disconnect() 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 1.2.3-korg 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 --- .../trex_control_plane/client/trex_hltapi.py | 158 ++++++++++++++++++--- .../client/trex_stateless_client.py | 36 +++-- .../client_utils/general_utils.py | 16 +++ .../trex_control_plane/common/trex_streams.py | 3 +- .../trex_control_plane/console/trex_console.py | 4 +- .../examples/stateless_example.py | 31 +++- 6 files changed, 213 insertions(+), 35 deletions(-) mode change 100644 => 100755 scripts/automation/trex_control_plane/examples/stateless_example.py (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/client/trex_hltapi.py b/scripts/automation/trex_control_plane/client/trex_hltapi.py index cc7005e8..92768ca4 100755 --- a/scripts/automation/trex_control_plane/client/trex_hltapi.py +++ b/scripts/automation/trex_control_plane/client/trex_hltapi.py @@ -3,6 +3,8 @@ import trex_root_path from client_utils.packet_builder import CTRexPktBuilder from trex_stateless_client import CTRexStatelessClient +from common.trex_streams import * +from client_utils.general_utils import id_count_gen import dpkt @@ -11,8 +13,8 @@ class CTRexHltApi(object): def __init__(self): self.trex_client = None self.connected = False - - pass + # self._stream_db = CStreamList() + self._port_data = {} # ----- session functions ----- # @@ -50,11 +52,12 @@ class CTRexHltApi(object): port_handle = {device: {port: port # since only supporting single TRex at the moment, 1:1 map for port in port_list} } - ret_dict.update({"status": 1, "log": None, "port_handle": port_handle, "offline": 0}) # ports are online + self.connected = True + self._port_data_init(port_list) return ret_dict def cleanup_session(self, port_list, maintain_lock=False): @@ -75,6 +78,7 @@ class CTRexHltApi(object): "log": None}) self.trex_client.disconnect() self.trex_client = None + self.connected = False return ret_dict def interface_config(self, port_handle, mode="config"): @@ -86,37 +90,150 @@ class CTRexHltApi(object): # ----- traffic functions ----- # def traffic_config(self, mode, port_handle, - l2_encap, mac_src, mac_dst, - l3_protocol, ip_src_addr, ip_dst_addr, l3_length, - transmit_mode, rate_pps): + l2_encap="ethernet_ii", mac_src="00:00:01:00:00:01", mac_dst="00:00:00:00:00:00", + l3_protocol="ipv4", ip_src_addr="0.0.0.0", ip_dst_addr="192.0.0.1", l3_length=110, + transmit_mode="continuous", rate_pps=100, + **kwargs): ALLOWED_MODES = ["create", "modify", "remove", "enable", "disable", "reset"] if mode not in ALLOWED_MODES: raise ValueError("mode must be one of the following values: {modes}".format(modes=ALLOWED_MODES)) if mode == "create": - # create a new stream with desired attributes - stream = CTRexHltApi.generate_stream(l2_encap, mac_src, mac_dst, - l3_protocol, ip_src_addr, ip_dst_addr, l3_length, - transmit_mode, rate_pps) - - - - pass + # create a new stream with desired attributes, starting by creating packet + try: + packet = CTRexHltApi.generate_stream(l2_encap, mac_src, mac_dst, + l3_protocol, ip_src_addr, ip_dst_addr, l3_length) + # set transmission attributes + tx_mode = CTxMode(transmit_mode, rate_pps, **kwargs) + # set rx_stats + rx_stats = CRxStats() # defaults with disabled + # join the generated data into stream + stream_obj = CStream() + stream_obj_params = {"enabled": True, + "self_start": True, + "next_stream_id": -1, + "isg": 0.0, + "mode": tx_mode, + "rx_stats": rx_stats, + "packet": packet} # vm is excluded from this list since CTRexPktBuilder obj is passed + stream_obj.load_data(**stream_obj_params) + except Exception as e: + # some exception happened during the stream creation + return {"status": 0, "log": str(e)} + # try adding the stream, until free stream_id is found + port_data = self._port_data.get(port_handle) + id_candidate = None + # TODO: change this to better implementation + while True: + id_candidate = port_data["stream_id_gen"].next() + response = self.trex_client.add_stream(stream_id=id_candidate, + stream_obj=stream_obj, + port_id=port_handle) + res_ok, log = CTRexHltApi.process_response(port_handle, response) + if res_ok: + # found non-taken stream_id on server + # save it for modifying needs + port_data["streams"].update({id_candidate: stream_obj}) + break + else: + # proceed to another iteration to use another id + continue + return {"status": 1, + "stream_id": id_candidate, + "log": None} else: raise NotImplementedError("mode '{0}' is not supported yet on TRex".format(mode)) def traffic_control(self, action, port_handle): - pass + ALLOWED_ACTIONS = ["clear_stats", "run", "stop", "sync_run"] + if action not in ALLOWED_ACTIONS: + raise ValueError("action must be one of the following values: {actions}".format(actions=ALLOWED_ACTIONS)) + # ret_dict = {"status": 0, "stopped": 1} + port_list = self.parse_port_list(port_handle) + if action == "run": + response = self.trex_client.start_traffic(port_id=port_list) + res_ok, log = CTRexHltApi.process_response(port_list, response) + if res_ok: + return {"status": 1, + "stopped": 0, + "log": None} + elif action == "stop": + response = self.trex_client.stop_traffic(port_id=port_list) + res_ok, log = CTRexHltApi.process_response(port_list, response) + if res_ok: + return {"status": 1, + "stopped": 1, + "log": None} + else: + raise NotImplementedError("action '{0}' is not supported yet on TRex".format(action)) + + # if we arrived here, this means that operation FAILED! + return {"status": 0, + "log": log} + def traffic_stats(self, port_handle, mode): - pass + ALLOWED_MODES = ["aggregate", "streams", "all"] + if mode not in ALLOWED_MODES: + raise ValueError("mode must be one of the following values: {modes}".format(modes=ALLOWED_MODES)) + # pass this function for now... + if mode == "aggregate": + # create a new stream with desired attributes, starting by creating packet + try: + packet = CTRexHltApi.generate_stream(l2_encap, mac_src, mac_dst, + l3_protocol, ip_src_addr, ip_dst_addr, l3_length) + # set transmission attributes + tx_mode = CTxMode(transmit_mode, rate_pps, **kwargs) + # set rx_stats + rx_stats = CRxStats() # defaults with disabled + # join the generated data into stream + stream_obj = CStream() + stream_obj_params = {"enabled": True, + "self_start": True, + "next_stream_id": -1, + "isg": 0.0, + "mode": tx_mode, + "rx_stats": rx_stats, + "packet": packet} # vm is excluded from this list since CTRexPktBuilder obj is passed + stream_obj.load_data(**stream_obj_params) + except Exception as e: + # some exception happened during the stream creation + return {"status": 0, "log": str(e)} + # try adding the stream, until free stream_id is found + port_data = self._port_data.get(port_handle) + id_candidate = None + # TODO: change this to better implementation + while True: + id_candidate = port_data["stream_id_gen"].next() + response = self.trex_client.add_stream(stream_id=id_candidate, + stream_obj=stream_obj, + port_id=port_handle) + res_ok, log = CTRexHltApi.process_response(port_handle, response) + if res_ok: + # found non-taken stream_id on server + # save it for modifying needs + port_data["streams"].update({id_candidate: stream_obj}) + break + else: + # proceed to another iteration to use another id + continue + return {"status": 1, + "stream_id": id_candidate, + "log": None} + else: + raise NotImplementedError("mode '{0}' is not supported yet on TRex".format(mode)) def get_aggregate_port_stats(self, port_handle): return self.traffic_stats(port_handle, mode="aggregate") def get_stream_stats(self, port_handle): - return self.traffic_stats(port_handle, mode="stream") + return self.traffic_stats(port_handle, mode="streams") # ----- internal functions ----- # + def _port_data_init(self, port_list): + for port in port_list: + self._port_data[port] = {"stream_id_gen": id_count_gen(), + "streams": {}} + @staticmethod def process_response(port_list, response): if isinstance(port_list, list): @@ -145,8 +262,7 @@ class CTRexHltApi(object): @staticmethod def generate_stream(l2_encap, mac_src, mac_dst, - l3_protocol, ip_src_addr, ip_dst_addr, l3_length, - transmit_mode, rate_pps): + l3_protocol, ip_src_addr, ip_dst_addr, l3_length): ALLOWED_L3_PROTOCOL = {"ipv4": dpkt.ethernet.ETH_TYPE_IP, "ipv6": dpkt.ethernet.ETH_TYPE_IP6, "arp": dpkt.ethernet.ETH_TYPE_ARP} @@ -177,9 +293,13 @@ class CTRexHltApi(object): pkt_bld.add_pkt_layer("l3", dpkt.ip.IP()) pkt_bld.set_ip_layer_addr("l3", "src", ip_src_addr) pkt_bld.set_ip_layer_addr("l3", "dst", ip_dst_addr) + pkt_bld.set_layer_attr("l3", "len", l3_length) else: raise NotImplementedError("l3_protocol '{0}' is not supported by TRex yet.".format(l3_protocol)) + pkt_bld.dump_pkt_to_pcap("stream_test.pcap") + return pkt_bld + if __name__ == "__main__": diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py index 3079ee5e..bbdcddbe 100755 --- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py @@ -62,7 +62,7 @@ class CTRexStatelessClient(object): continue if bad_ids: # Some port IDs are not according to desires status - raise RuntimeError("The requested method ('{0}') cannot be invoked since port IDs {1} are not" + raise RuntimeError("The requested method ('{0}') cannot be invoked since port IDs {1} are not " "at allowed stated".format(func.__name__, list(bad_ids))) else: return func(self, *args, **kwargs) @@ -229,13 +229,15 @@ class CTRexStatelessClient(object): for p_id in port_ids] rc, resp_list = self.transmit_batch(commands) if rc: - self._process_batch_result(commands, resp_list, self._handle_start_traffic_response) + return self._process_batch_result(commands, resp_list, self._handle_start_traffic_response, + success_test=self.ack_success_test) else: params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} command = RpcCmdData("start_traffic", params) - self._handle_start_traffic_response(command, self.transmit(command.method, command.params)) - return + return self._handle_start_traffic_response(command, + self.transmit(command.method, command.params), + self.ack_success_test) @force_status(owned=False, active_and_owned=True) def stop_traffic(self, port_id=None): @@ -248,13 +250,15 @@ class CTRexStatelessClient(object): for p_id in port_ids] rc, resp_list = self.transmit_batch(commands) if rc: - self._process_batch_result(commands, resp_list, self._handle_stop_traffic_response) + return self._process_batch_result(commands, resp_list, self._handle_stop_traffic_response, + success_test=self.ack_success_test) else: params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} command = RpcCmdData("stop_traffic", params) - self._handle_start_traffic_response(command, self.transmit(command.method, command.params)) - return + return self._handle_start_traffic_response(command, + self.transmit(command.method, command.params), + self.ack_success_test) def get_global_stats(self): command = RpcCmdData("get_global_stats", {}) @@ -375,12 +379,20 @@ class CTRexStatelessClient(object): return RpcResponseStatus(False, port_id, response.data) def _handle_start_traffic_response(self, request, response, success_test): - if response.success: - self._active_ports.add(request.get("port_id")) + port_id = request.params.get("port_id") + if success_test(response): + self._active_ports.add(port_id) + return RpcResponseStatus(True, port_id, "Traffic started") + else: + return RpcResponseStatus(False, port_id, response.data) - def _handle_stop_traffic_response(self, request, response): - if response.success: - self._active_ports.remove(request.get("port_id")) + def _handle_stop_traffic_response(self, request, response, success_test): + port_id = request.params.get("port_id") + if success_test(response): + self._active_ports.remove(port_id) + return RpcResponseStatus(True, port_id, "Traffic stopped") + else: + return RpcResponseStatus(False, port_id, response.data) def _handle_get_global_stats_response(self, request, response, success_test): if response.success: diff --git a/scripts/automation/trex_control_plane/client_utils/general_utils.py b/scripts/automation/trex_control_plane/client_utils/general_utils.py index 5488b9dd..3c025608 100755 --- a/scripts/automation/trex_control_plane/client_utils/general_utils.py +++ b/scripts/automation/trex_control_plane/client_utils/general_utils.py @@ -75,6 +75,22 @@ def random_id_gen(length=8): return_id += random.choice(id_chars) yield return_id +def id_count_gen(): + """ + A generator for creating an increasing id for objects, starting from 0 + + :parameters: + None + + :return: + an id (unsigned int) with each next() request. + """ + return_id = 0 + while True: + yield return_id + return_id += 1 + + if __name__ == "__main__": pass diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py index 750da198..bb4c72ca 100755 --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -23,7 +23,7 @@ class CStreamList(object): if name in self.streams_list: raise NameError("A stream with this name already exists on this list.") self.streams_list[name]=stream_obj - return + return name def remove_stream(self, name): popped = self.streams_list.pop(name) @@ -184,6 +184,7 @@ class CStream(object): if isinstance(kwargs[k], CTRexPktBuilder): if "vm" not in kwargs: self.load_packet_obj(kwargs[k]) + break # vm field check is skipped else: raise ValueError("When providing packet object with a CTRexPktBuilder, vm parameter " "should not be supplied") 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 diff --git a/scripts/automation/trex_control_plane/examples/stateless_example.py b/scripts/automation/trex_control_plane/examples/stateless_example.py old mode 100644 new mode 100755 index f97bce4c..bb0fe983 --- a/scripts/automation/trex_control_plane/examples/stateless_example.py +++ b/scripts/automation/trex_control_plane/examples/stateless_example.py @@ -1 +1,30 @@ -__author__ = 'danklei' +#!/router/bin/python + +import trex_root_path +from client.trex_hltapi import CTRexHltApi + +if __name__ == "__main__": + port_list = [1,2] + try: + hlt_client = CTRexHltApi() + con = hlt_client.connect("localhost", port_list, "danklei", break_locks=True, reset=True)#, port=6666) + print con + + res = hlt_client.traffic_config("create", 1)#, ip_src_addr="2000.2.2") + print res + res = hlt_client.traffic_config("create", 2)#, ip_src_addr="2000.2.2") + print res + + res = hlt_client.traffic_control("run", [1, 2])#, ip_src_addr="2000.2.2") + print res + + res = hlt_client.traffic_control("stop", [1, 2])#, ip_src_addr="2000.2.2") + print res + + + + except Exception as e: + raise + finally: + res = hlt_client.cleanup_session(port_list) + print res \ No newline at end of file -- cgit 1.2.3-korg 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! --- .../client/trex_stateless_client.py | 21 +- .../trex_control_plane/console/trex_console.py | 238 ++++++++++++--------- 2 files changed, 151 insertions(+), 108 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py index bbdcddbe..1df07e2a 100755 --- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py @@ -89,6 +89,9 @@ class CTRexStatelessClient(object): self.__err_log = ver_info return self._server_version if self._server_version else "Unknown" + def is_connected(self): + return self.comm_link.is_connected + # ----- user-access methods ----- # def connect(self): rc, err = self.comm_link.connect() @@ -114,6 +117,13 @@ class CTRexStatelessClient(object): def get_port_count(self): return self.system_info.get("port_count") + def get_port_ids(self, as_str=False): + port_ids = range(self.get_port_count()) + if as_str: + return " ".join(str(p) for p in port_ids) + else: + return port_ids + def get_acquired_ports(self): return self._conn_handler.keys() @@ -417,7 +427,7 @@ class CTRexStatelessClient(object): # check each item of the sequence return all([self._is_ports_valid(port) for port in port_id]) - elif (isinstance(port_id, int)) and (port_id > 0) and (port_id <= self.get_port_count()): + elif (isinstance(port_id, int)) and (port_id >= 0) and (port_id <= self.get_port_count()): return True else: return False @@ -450,13 +460,20 @@ class CTRexStatelessClient(object): self.port = port self.rpc_link = JsonRpcClient(self.server, self.port) + @property + def is_connected(self): + if not self.virtual: + return self.rpc_link.connected + else: + return True + def connect(self): if not self.virtual: return self.rpc_link.connect() def disconnect(self): if not self.virtual: - self.rpc_link.disconnect() + return self.rpc_link.disconnect() def transmit(self, method_name, params={}): if self.virtual: 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 1.2.3-korg 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 --- .../client/trex_stateless_client.py | 29 +++ .../trex_control_plane/common/text_opts.py | 27 ++- .../trex_control_plane/console/trex_console.py | 234 +++++++++++++++------ 3 files changed, 227 insertions(+), 63 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py index 1df07e2a..0fff9b36 100755 --- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py @@ -180,6 +180,27 @@ class CTRexStatelessClient(object): "stream": stream_obj.dump()} return self.transmit("add_stream", params) + @force_status(owned=True) + def add_stream_pack(self, port_id=None, *stream_packs): + if not self._is_ports_valid(port_id): + raise ValueError("Provided illegal port id input") + + # since almost every run contains more than one transaction with server, handle all as batch mode + port_ids = set(port_id) # convert to set to avoid duplications + commands = [] + for stream_pack in stream_packs: + commands.extend([RpcCmdData("add_stream", {"port_id": p_id, + "handler": self._conn_handler.get(p_id), + "stream_id": stream_pack.stream_id, + "stream": stream_pack.stream} + ) + for p_id in port_ids] + ) + res_ok, resp_list = self.transmit_batch(commands) + if res_ok: + return self._process_batch_result(commands, resp_list, self._handle_add_stream_response, + success_test=self.ack_success_test) + @force_status(owned=True) def remove_stream(self, stream_id, port_id=None): if not self._is_ports_valid(port_id): @@ -373,6 +394,14 @@ class CTRexStatelessClient(object): else: return RpcResponseStatus(False, port_id, response.data) + def _handle_add_stream_response(self, request, response, success_test): + port_id = request.params.get("port_id") + stream_id = request.params.get("stream_id") + if success_test(response): + return RpcResponseStatus(True, port_id, "Stream {0} added".format(stream_id)) + else: + return RpcResponseStatus(False, port_id, response.data) + def _handle_remove_streams_response(self, request, response, success_test): port_id = request.params.get("port_id") if success_test(response): diff --git a/scripts/automation/trex_control_plane/common/text_opts.py b/scripts/automation/trex_control_plane/common/text_opts.py index 8ab03eeb..0d8323db 100644 --- a/scripts/automation/trex_control_plane/common/text_opts.py +++ b/scripts/automation/trex_control_plane/common/text_opts.py @@ -1,4 +1,5 @@ - +import json +import re TEXT_CODES = {'bold': {'start': '\x1b[1m', 'end': '\x1b[22m'}, @@ -65,7 +66,29 @@ def format_text(text, *args): func = FUNC_DICT.get(i) if func: return_string = func(return_string) - return return_string + return + +# pretty print for JSON +def pretty_json (json_str, use_colors = True): + pretty_str = json.dumps(json.loads(json_str), indent = 4, separators=(',', ': '), sort_keys = True) + + if not use_colors: + return pretty_str + + try: + # int numbers + pretty_str = re.sub(r'([ ]*:[ ]+)(\-?[1-9][0-9]*[^.])',r'\1{0}'.format(blue(r'\2')), pretty_str) + # float + pretty_str = re.sub(r'([ ]*:[ ]+)(\-?[1-9][0-9]*\.[0-9]+)',r'\1{0}'.format(magenta(r'\2')), pretty_str) + # # strings + # + pretty_str = re.sub(r'([ ]*:[ ]+)("[^"]*")',r'\1{0}'.format(red(r'\2')), pretty_str) + pretty_str = re.sub(r"('[^']*')", r'{0}\1{1}'.format(TEXT_CODES['magenta']['start'], + TEXT_CODES['red']['start']), pretty_str) + except : + pass + + return pretty_str if __name__ == "__main__": 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 1.2.3-korg 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/common/text_opts.py | 2 +- .../trex_control_plane/console/trex_console.py | 69 +++++++++++++++------- 2 files changed, 48 insertions(+), 23 deletions(-) mode change 100644 => 100755 scripts/automation/trex_control_plane/common/text_opts.py (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/common/text_opts.py b/scripts/automation/trex_control_plane/common/text_opts.py old mode 100644 new mode 100755 index 0d8323db..4d1cb0fd --- a/scripts/automation/trex_control_plane/common/text_opts.py +++ b/scripts/automation/trex_control_plane/common/text_opts.py @@ -66,7 +66,7 @@ def format_text(text, *args): func = FUNC_DICT.get(i) if func: return_string = func(return_string) - return + return return_string # pretty print for JSON def pretty_json (json_str, use_colors = True): 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 1.2.3-korg 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. --- .../client/trex_stateless_client.py | 7 +- .../trex_control_plane/common/text_opts.py | 5 + .../trex_control_plane/console/trex_console.py | 162 ++++++++++++--------- 3 files changed, 105 insertions(+), 69 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py index 0fff9b36..4e861585 100755 --- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py @@ -62,8 +62,8 @@ class CTRexStatelessClient(object): continue if bad_ids: # Some port IDs are not according to desires status - raise RuntimeError("The requested method ('{0}') cannot be invoked since port IDs {1} are not " - "at allowed stated".format(func.__name__, list(bad_ids))) + raise ValueError("The requested method ('{0}') cannot be invoked since port IDs {1} are not " + "at allowed states".format(func.__name__, list(bad_ids))) else: return func(self, *args, **kwargs) return wrapper_f @@ -127,6 +127,9 @@ class CTRexStatelessClient(object): def get_acquired_ports(self): return self._conn_handler.keys() + def get_active_ports(self): + return list(self._active_ports) + def acquire(self, port_id, force=False): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") diff --git a/scripts/automation/trex_control_plane/common/text_opts.py b/scripts/automation/trex_control_plane/common/text_opts.py index 4d1cb0fd..06c2c056 100755 --- a/scripts/automation/trex_control_plane/common/text_opts.py +++ b/scripts/automation/trex_control_plane/common/text_opts.py @@ -13,6 +13,8 @@ TEXT_CODES = {'bold': {'start': '\x1b[1m', 'end': '\x1b[39m'}, 'green': {'start': '\x1b[32m', 'end': '\x1b[39m'}, + 'yellow': {'start': '\x1b[33m', + 'end': '\x1b[39m'}, 'underline': {'start': '\x1b[4m', 'end': '\x1b[24m'}} @@ -40,6 +42,8 @@ def magenta(text): def green(text): return text_attribute(text, 'green') +def yellow(text): + return text_attribute(text, 'yellow') def underline(text): return text_attribute(text, 'underline') @@ -54,6 +58,7 @@ def text_attribute(text, attribute): FUNC_DICT = {'blue': blue, 'bold': bold, 'green': green, + 'yellow': yellow, 'cyan': cyan, 'magenta': magenta, 'underline': underline, 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 1.2.3-korg