From cbc645cba025f2098031350fc1323e6ffff33633 Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 18 Aug 2015 10:26:51 +0300 Subject: new files for Python console --- src/console/trex_rpc_client.py | 101 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/console/trex_rpc_client.py (limited to 'src/console/trex_rpc_client.py') diff --git a/src/console/trex_rpc_client.py b/src/console/trex_rpc_client.py new file mode 100644 index 00000000..e6ff5fee --- /dev/null +++ b/src/console/trex_rpc_client.py @@ -0,0 +1,101 @@ + +import zmq +import json +from time import sleep + +class RpcClient(): + + def create_jsonrpc_v2 (self, method_name, params = {}, id = None): + msg = {} + msg["jsonrpc"] = "2.0" + msg["method"] = method_name + + msg["params"] = {} + for key, value in params.iteritems(): + msg["params"][key] = value + + msg["id"] = id + + return json.dumps(msg) + + def invoke_rpc_method (self, method_name, params = {}, block = True): + msg = self.create_jsonrpc_v2(method_name, params, id = 1) + + if self.verbose: + print "\nSending Request To Server: " + str(msg) + "\n" + + self.socket.send(msg) + + got_response = False + + if block: + response = self.socket.recv() + got_response = True + else: + for i in xrange(0 ,5): + try: + response = self.socket.recv(flags = zmq.NOBLOCK) + got_response = True + break + except zmq.error.Again: + sleep(0.1) + + if not got_response: + return False, "Failed To Get Server Response" + + if self.verbose: + print "Server Response: " + str(response) + "\n" + + # decode + response_json = json.loads(response) + + if (response_json.get("jsonrpc") != "2.0"): + return False, "Bad Server Response: " + str(response) + + if ("error" in response_json): + return False, "Server Has Reported An Error: " + str(response) + + if ("result" not in response_json): + return False, "Bad Server Response: " + str(response) + + return True, response_json["result"] + + + def ping_rpc_server (self): + + return self.invoke_rpc_method("rpc_ping", block = False) + + + def query_rpc_server (self): + return self.invoke_rpc_method("rpc_get_reg_cmds") + + def __init__ (self, port): + self.context = zmq.Context() + + # Socket to talk to server + self.transport = "tcp://localhost:{0}".format(port) + + self.verbose = False + + def set_verbose (self, mode): + self.verbose = mode + + def connect (self): + + print "\nConnecting To RPC Server On {0}".format(self.transport) + + self.socket = self.context.socket(zmq.REQ) + self.socket.connect(self.transport) + + # ping the server + rc, err = self.ping_rpc_server() + if not rc: + self.context.destroy(linger = 0) + raise Exception(err) + + #print "Connection Established !\n" + print "[SUCCESS]\n" + + + + -- cgit 1.2.3-korg From 65b3e045334ce93162fadc85ea241b8b7667482d Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 18 Aug 2015 13:22:53 +0300 Subject: draft --- src/console/trex_console.py | 38 +++++++++++++++-- src/console/trex_rpc_client.py | 12 ++++-- .../src/commands/trex_rpc_cmd_general.cpp | 47 ++++++++++++++++++++++ src/rpc-server/src/commands/trex_rpc_cmds.h | 29 +++++++++++++ src/rpc-server/src/trex_rpc_cmds_table.cpp | 9 ++++- 5 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 src/rpc-server/src/commands/trex_rpc_cmd_general.cpp (limited to 'src/console/trex_rpc_client.py') diff --git a/src/console/trex_console.py b/src/console/trex_console.py index 404a2ee0..3e452bf5 100755 --- a/src/console/trex_console.py +++ b/src/console/trex_console.py @@ -1,6 +1,8 @@ #!/usr/bin/python # -*- coding: utf-8 -*- import cmd +import json + from trex_rpc_client import RpcClient class TrexConsole(cmd.Cmd): @@ -12,12 +14,18 @@ class TrexConsole(cmd.Cmd): self.intro = "\n-=TRex Console V1.0=-\n" self.rpc_client = rpc_client self.verbose = False + rc, msg = self.rpc_client.query_rpc_server() + + if rc: + lst = msg.split('\n') + self.supported_rpc = [str(x) for x in lst if x] # 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\nusage: verbose [on/off]\n''' if line == "": @@ -34,7 +42,7 @@ class TrexConsole(cmd.Cmd): else: print "please specify 'on' or 'off'\n" - + # query the server for registered commands def do_query_server(self, line): '''\nquery the RPC server for supported remote commands\n''' rc, msg = self.rpc_client.query_rpc_server() @@ -44,7 +52,7 @@ class TrexConsole(cmd.Cmd): print "RPC server supports the following commands: \n\n" + msg def do_ping (self, line): - '''pings the RPC server \n''' + '''pings the RPC server\n''' print "Pinging RPC server" rc, msg = self.rpc_client.ping_rpc_server() @@ -53,6 +61,23 @@ class TrexConsole(cmd.Cmd): else: print "[FAILED]\n" + def do_rpc (self, line): + '''Launches a RPC on the server\n''' + if line == "": + print "Please provide method name\n" + return + + rc, msg = self.rpc_client.invoke_rpc_method(line) + if rc: + print "[SUCCESS]\n" + else: + print "[FAILED]\n" + + print "Server Response:\n\n{0}\n".format(json.dumps(msg)) + + def complete_rpc (self, text, line, begidx, endidx): + return [x for x in self.supported_rpc if x.startswith(text)] + def do_quit(self, line): '''\nexit the client\n''' return True @@ -73,8 +98,13 @@ def main (): exit(-1) # console - console = TrexConsole(rpc_client) - console.cmdloop() + try: + console = TrexConsole(rpc_client) + console.cmdloop() + except KeyboardInterrupt as e: + print "\n\n*** Caught Ctrl + C... Exiting...\n\n" + return if __name__ == '__main__': main() + diff --git a/src/console/trex_rpc_client.py b/src/console/trex_rpc_client.py index e6ff5fee..ac4aa298 100644 --- a/src/console/trex_rpc_client.py +++ b/src/console/trex_rpc_client.py @@ -50,13 +50,15 @@ class RpcClient(): response_json = json.loads(response) if (response_json.get("jsonrpc") != "2.0"): - return False, "Bad Server Response: " + str(response) + return False, "Malfromed Response ({0})".format(str(response)) + # error reported by server if ("error" in response_json): - return False, "Server Has Reported An Error: " + str(response) + return False, response_json["error"]["message"] + # if no error there should be a result if ("result" not in response_json): - return False, "Bad Server Response: " + str(response) + return False, "Malfromed Response ({0})".format(str(response)) return True, response_json["result"] @@ -97,5 +99,9 @@ class RpcClient(): print "[SUCCESS]\n" + def __del__ (self): + print "Shutting down RPC client\n" + self.context.destroy(linger = 0) + diff --git a/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp new file mode 100644 index 00000000..2be4a76f --- /dev/null +++ b/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp @@ -0,0 +1,47 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include "trex_rpc_cmds.h" +#include <../linux_dpdk/version.h> + +using namespace std; + +/** + * get status + * + */ +TrexRpcCommand::rpc_cmd_rc_e +TrexRpcCmdGetStatus::_run(const Json::Value ¶ms, Json::Value &result) { + + /* validate count */ + if (params.size() != 0) { + return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR); + } + + Json::Value §ion = result["result"]; + + section["general"]["version"] = VERSION_BUILD_NUM; + section["general"]["build_date"] = get_build_date(); + section["general"]["build_time"] = get_build_time(); + section["general"]["version_user"] = VERSION_USER; + + return (RPC_CMD_OK); +} + diff --git a/src/rpc-server/src/commands/trex_rpc_cmds.h b/src/rpc-server/src/commands/trex_rpc_cmds.h index 44b72c4c..0778b75d 100644 --- a/src/rpc-server/src/commands/trex_rpc_cmds.h +++ b/src/rpc-server/src/commands/trex_rpc_cmds.h @@ -28,6 +28,11 @@ limitations under the License. /* all the RPC commands decl. goes here */ /******************* test section ************/ + +/** + * add + * + */ class TrexRpcCmdTestAdd : public TrexRpcCommand { public: TrexRpcCmdTestAdd() : TrexRpcCommand("rpc_test_add") {} @@ -35,6 +40,10 @@ protected: virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); }; +/** + * sub + * + */ class TrexRpcCmdTestSub : public TrexRpcCommand { public: TrexRpcCmdTestSub() : TrexRpcCommand("rpc_test_sub") {} ; @@ -42,6 +51,10 @@ protected: virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); }; +/** + * ping + * + */ class TrexRpcCmdPing : public TrexRpcCommand { public: TrexRpcCmdPing() : TrexRpcCommand("rpc_ping") {}; @@ -49,6 +62,10 @@ protected: virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); }; +/** + * get all registered commands + * + */ class TrexRpcCmdGetReg : public TrexRpcCommand { public: TrexRpcCmdGetReg() : TrexRpcCommand("rpc_get_reg_cmds") {}; @@ -56,5 +73,17 @@ protected: virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); }; +/** + * get status + * + */ +class TrexRpcCmdGetStatus : public TrexRpcCommand { +public: + TrexRpcCmdGetStatus() : TrexRpcCommand("rpc_get_status") {}; +protected: + virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); +}; + + /**************** test section end *************/ #endif /* __TREX_RPC_CMD_H__ */ diff --git a/src/rpc-server/src/trex_rpc_cmds_table.cpp b/src/rpc-server/src/trex_rpc_cmds_table.cpp index 7635f14f..04a56389 100644 --- a/src/rpc-server/src/trex_rpc_cmds_table.cpp +++ b/src/rpc-server/src/trex_rpc_cmds_table.cpp @@ -32,6 +32,7 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() { register_command(new TrexRpcCmdTestSub()); register_command(new TrexRpcCmdPing()); register_command(new TrexRpcCmdGetReg()); + register_command(new TrexRpcCmdGetStatus()); } TrexRpcCommandsTable::~TrexRpcCommandsTable() { @@ -41,7 +42,13 @@ TrexRpcCommandsTable::~TrexRpcCommandsTable() { } TrexRpcCommand * TrexRpcCommandsTable::lookup(const string &method_name) { - return m_rpc_cmd_table[method_name]; + auto search = m_rpc_cmd_table.find(method_name); + + if (search != m_rpc_cmd_table.end()) { + return search->second; + } else { + return NULL; + } } -- cgit 1.2.3-korg From ace4f5990ef18bb3a76d042b60d7a8af02bcd357 Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 18 Aug 2015 16:21:53 +0300 Subject: added status panel --- src/console/trex_console.py | 5 + src/console/trex_rpc_client.py | 10 +- src/console/trex_status.py | 290 +++++++++++++++++++++ src/rpc-server/include/trex_rpc_server_api.h | 5 + .../src/commands/trex_rpc_cmd_general.cpp | 3 +- src/rpc-server/src/trex_rpc_server.cpp | 14 +- 6 files changed, 324 insertions(+), 3 deletions(-) create mode 100755 src/console/trex_status.py (limited to 'src/console/trex_rpc_client.py') diff --git a/src/console/trex_console.py b/src/console/trex_console.py index 3e452bf5..ca4c7e86 100755 --- a/src/console/trex_console.py +++ b/src/console/trex_console.py @@ -4,6 +4,7 @@ import cmd import json from trex_rpc_client import RpcClient +import trex_status class TrexConsole(cmd.Cmd): """Trex Console""" @@ -78,6 +79,10 @@ class TrexConsole(cmd.Cmd): 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''' + trex_status.show_trex_status(self.rpc_client) + def do_quit(self, line): '''\nexit the client\n''' return True diff --git a/src/console/trex_rpc_client.py b/src/console/trex_rpc_client.py index ac4aa298..04dd7727 100644 --- a/src/console/trex_rpc_client.py +++ b/src/console/trex_rpc_client.py @@ -24,7 +24,13 @@ class RpcClient(): if self.verbose: print "\nSending Request To Server: " + str(msg) + "\n" - self.socket.send(msg) + if block: + self.socket.send(msg) + else: + try: + self.socket.send(msg, flags = zmq.NOBLOCK) + except zmq.error.ZMQError: + return False, "Failed To Get Server Response" got_response = False @@ -67,6 +73,8 @@ class RpcClient(): return self.invoke_rpc_method("rpc_ping", block = False) + def get_rpc_server_status (self): + return self.invoke_rpc_method("rpc_get_status") def query_rpc_server (self): return self.invoke_rpc_method("rpc_get_reg_cmds") diff --git a/src/console/trex_status.py b/src/console/trex_status.py new file mode 100755 index 00000000..a17c2589 --- /dev/null +++ b/src/console/trex_status.py @@ -0,0 +1,290 @@ +from time import sleep + +import os + +import curses +from curses import panel +import random +import collections +import operator +import datetime + +g_curses_active = False + +# +def percentage (a, total): + x = int ((float(a) / total) * 100) + return str(x) + "%" + +# panel object +class TrexStatusPanel(): + def __init__ (self, h, l, y, x, headline): + self.h = h + self.l = l + self.y = y + self.x = x + self.headline = headline + + self.win = curses.newwin(h, l, y, x) + self.win.erase() + self.win.box() + + self.win.addstr(1, 2, headline, curses.A_UNDERLINE) + self.win.refresh() + + panel.new_panel(self.win) + self.panel = panel.new_panel(self.win) + self.panel.top() + + def clear (self): + self.win.erase() + self.win.box() + self.win.addstr(1, 2, self.headline, curses.A_UNDERLINE) + + def getwin (self): + return self.win + +def float_to_human_readable (size, suffix = "bps"): + for unit in ['','K','M','G']: + if abs(size) < 1024.0: + return "%3.1f %s%s" % (size, unit, suffix) + size /= 1024.0 + return "NaN" + +# status object +class TrexStatus(): + def __init__ (self, stdscr, rpc_client): + self.stdscr = stdscr + self.log = [] + self.rpc_client = rpc_client + + self.get_server_info() + + def get_server_info (self): + rc, msg = self.rpc_client.get_rpc_server_status() + + if rc: + self.server_status = msg + else: + self.server_status = None + + def add_log_event (self, msg): + self.log.append("[{0}] {1}".format(str(datetime.datetime.now().time()), msg)) + + def add_panel (self, h, l, y, x, headline): + win = curses.newwin(h, l, y, x) + win.erase() + win.box() + + win.addstr(1, 2, headline) + win.refresh() + + panel.new_panel(win) + panel1 = panel.new_panel(win) + panel1.top() + + return win, panel1 + + def update_info (self): + if self.server_status == None: + return + + self.info_panel.clear() + + self.info_panel.getwin().addstr(3, 2, "{:<30} {:30}".format("Version:", self.server_status["general"]["version"])) + self.info_panel.getwin().addstr(4, 2, "{:<30} {:30}".format("Build:", + self.server_status["general"]["build_date"] + " @ " + self.server_status["general"]["build_time"] + " by " + self.server_status["general"]["version_user"])) + + self.info_panel.getwin().addstr(5, 2, "{:<30} {:30}".format("Server Uptime:", self.server_status["general"]["uptime"])) + #self.ft_panel.clear() + + #ft_section_y = 3 + #self.ft_panel.getwin().addstr(ft_section_y, 2,"General Info:", curses.A_UNDERLINE) + + #self.ft_panel.getwin().addstr(ft_section_y, 2, "{:<30} {:<30,}".format("Total Flows Opened:", ft_stats["total-opened-flows"])) + #ft_section_y = ft_section_y + 1 + #self.ft_panel.getwin().addstr(ft_section_y, 2, "{:<30} {:<30,}".format("Total Flows Closed:", ft_stats["total-closed-flows"])) + #ft_section_y = ft_section_y + 1 + #self.ft_panel.getwin().addstr(ft_section_y, 2, "{:<30} {:<30,}".format("Current Active Flows:", ft_stats["active-flows"])) + #ft_section_y = ft_section_y + 1 + #self.ft_panel.getwin().addstr(ft_section_y, 2, "{:<30} {:<30,}".format("Flow Allocation Errors:", ft_stats["allocation_err"])) + + def update_general (self, gen_stats): + + if not gen_stats: + return + + transport_info_section_y = 3 + general_info_section_y = int(self.cls_panel.h * 0.5) + + self.general_panel.clear() + + # transport layer info + self.general_panel.getwin().addstr(transport_info_section_y, 2, "{:<30} {:^10} {:^5} {:^10}".format("Total Tx Rate:", + float_to_human_readable(gen_stats["total-rx-bps"]), + "/", + float_to_human_readable(gen_stats["total-rx-pps"], suffix = "pps"))) + transport_info_section_y += 2 + + + self.general_panel.getwin().addstr(transport_info_section_y, 2, "{:<30} {:^6.2f} %".format("DP Core Util.:", gen_stats["cpu-util"])); + + transport_info_section_y += 2 + + for i in range(1, 3): + self.general_panel.getwin().addstr(transport_info_section_y, 2, "{:<30} {:^10} {:^5} {:^10}".format("Port {0} Rx:".format(i), + float_to_human_readable(gen_stats["port " + str(i)]["total-rx-bps"]), + "/", + float_to_human_readable(gen_stats["port " + str(i)]["total-rx-pps"], suffix = "pps"))) + transport_info_section_y += 1 + + + self.general_panel.getwin().addstr(general_info_section_y, 2,"General Info:", curses.A_UNDERLINE) + general_info_section_y = general_info_section_y + 2 + + self.general_panel.getwin().addstr(general_info_section_y, 2, "{:<30} {:<30}".format("VNBAR Main Process PID:", os.getppid())) + general_info_section_y = general_info_section_y + 1 + self.general_panel.getwin().addstr(general_info_section_y, 2, "{:<30} {:<30}".format("ZMQ client online at:", vnbar_ipc.VnbarIpc.get_zmq_transport_name())) + + + # v2 + def update_cls (self, pd_stats): + if not pd_stats: + return + + self.cls_panel.clear() + + section_start = 3 + section_size = (self.cls_panel.h / 2) - 5 + + for port_name, pd in sorted(pd_stats.iteritems()): + if pd == None: + continue + + # sort by bandwidth + pd = collections.OrderedDict(sorted(pd.items(), key=operator.itemgetter(1), reverse = True)) + + # restart the line index + line_index = 0 + + # headline + self.cls_panel.getwin().addstr(section_start + line_index, 2, "{0}:".format(port_name), curses.A_BOLD | curses.A_UNDERLINE) + line_index += 1 + + cls_str = "{:^45} {:^20} {:^20} {:^20}".format("Protocol Name", "Byte Count", "Packet Count", "B/W Perc.") + self.cls_panel.getwin().addstr(section_start + line_index, 2, cls_str) + line_index += 2 + + # protocols + proto_index = 0 + proto_count = len(pd) + + total_bandwidth = sum([i['bytes'] for i in pd.values()]) + + for proto_name, cnts in pd.iteritems(): + proto_str = "{:<45} {:^20,} {:^20,} {:^20}".format(proto_name, cnts['bytes'], cnts['pkts'], percentage(cnts['bytes'], total_bandwidth) ) + proto_index = proto_index + 1 + + if line_index > section_size: + self.cls_panel.getwin().addstr(section_start + line_index, 2, "<...{0} More...>".format(proto_count - proto_index), (curses.A_DIM if ((line_index % 2) == 0) else curses.A_BOLD)) + break + + self.cls_panel.getwin().addstr(section_start + line_index, 2, proto_str, (curses.A_DIM if ((line_index % 2) == 0) else curses.A_BOLD)) + + line_index += 1 + + section_start = section_start + section_size + 3 + + + def update_control (self): + self.control_panel.clear() + + self.control_panel.getwin().addstr(1, 2, "'f' - freeze, 'c' - clear stats, 'p' - ping server, 'q' - quit") + + index = 3 + + cut = len(self.log) - 4 + if cut < 0: + cut = 0 + + for l in self.log[cut:]: + self.control_panel.getwin().addstr(index, 2, l) + index += 1 + + def run (self): + try: + curses.curs_set(0) + except: + pass + + curses.use_default_colors() + self.stdscr.nodelay(1) + curses.nonl() + curses.noecho() + + self.max_y = self.stdscr.getmaxyx()[0] + self.max_x = self.stdscr.getmaxyx()[1] + + # create cls panel + self.main_panel = TrexStatusPanel(int(self.max_y * 0.8), self.max_x / 2, 0,0, "Trex Activity:") + + self.general_panel = TrexStatusPanel(int(self.max_y * 0.6), self.max_x / 2, 0, self.max_x /2, "General Statistics:") + + self.info_panel = TrexStatusPanel(int(self.max_y * 0.2), self.max_x / 2, int(self.max_y * 0.6), self.max_x /2, "Server Info:") + + self.control_panel = TrexStatusPanel(int(self.max_y * 0.2), self.max_x , int(self.max_y * 0.8), 0, "") + + panel.update_panels(); self.stdscr.refresh() + + self.update_active = True + while (True): + ch = self.stdscr.getch() + + if (ch != curses.ERR): + # stop/start status + if (ch == ord('f')): + self.update_active = not self.update_active + self.add_log_event("Update continued" if self.update_active else "Update stopped") + + elif (ch == ord('p')): + self.add_log_event("Pinging RPC server") + rc, msg = self.rpc_client.ping_rpc_server() + if rc: + self.add_log_event("Server replied") + else: + self.add_log_event("Failed to get reply") + + # c - clear stats + elif (ch == ord('c')): + self.add_log_event("Statistics cleared") + + elif (ch == ord('q')): + break + else: + self.add_log_event("Unknown key pressed {0}".format("'" + chr(ch) + "'" if chr(ch).isalpha() else "")) + + self.update_control() + self.update_info() + + panel.update_panels(); + self.stdscr.refresh() + sleep(0.2) + + +def show_trex_status_internal (stdscr, rpc_client): + trex_status = TrexStatus(stdscr, rpc_client) + trex_status.run() + +def show_trex_status (rpc_client): + + try: + curses.wrapper(show_trex_status_internal, rpc_client) + except KeyboardInterrupt: + curses.endwin() + +def cleanup (): + try: + curses.endwin() + except: + pass + diff --git a/src/rpc-server/include/trex_rpc_server_api.h b/src/rpc-server/include/trex_rpc_server_api.h index 5f567a5c..bb455be2 100644 --- a/src/rpc-server/include/trex_rpc_server_api.h +++ b/src/rpc-server/include/trex_rpc_server_api.h @@ -119,8 +119,13 @@ public: void start(); void stop(); + static const std::string &get_server_uptime() { + return s_server_uptime; + } + private: std::vector m_servers; + static const std::string s_server_uptime; }; #endif /* __TREX_RPC_SERVER_API_H__ */ diff --git a/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp index 2be4a76f..581f3a02 100644 --- a/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp @@ -20,6 +20,7 @@ limitations under the License. */ #include "trex_rpc_cmds.h" #include <../linux_dpdk/version.h> +#include using namespace std; @@ -41,7 +42,7 @@ TrexRpcCmdGetStatus::_run(const Json::Value ¶ms, Json::Value &result) { section["general"]["build_date"] = get_build_date(); section["general"]["build_time"] = get_build_time(); section["general"]["version_user"] = VERSION_USER; - + section["general"]["uptime"] = TrexRpcServer::get_server_uptime(); return (RPC_CMD_OK); } diff --git a/src/rpc-server/src/trex_rpc_server.cpp b/src/rpc-server/src/trex_rpc_server.cpp index 34e60c96..17eeec6d 100644 --- a/src/rpc-server/src/trex_rpc_server.cpp +++ b/src/rpc-server/src/trex_rpc_server.cpp @@ -25,7 +25,6 @@ limitations under the License. #include #include - /************** RPC server interface ***************/ TrexRpcServerInterface::TrexRpcServerInterface(const TrexRpcServerConfig &cfg) : m_cfg(cfg) { @@ -70,6 +69,19 @@ bool TrexRpcServerInterface::is_running() { /************** RPC server *************/ +static const std::string +get_current_date_time() { + time_t now = time(0); + struct tm tstruct; + char buf[80]; + tstruct = *localtime(&now); + strftime(buf, sizeof(buf), "%d-%b-%Y / %X", &tstruct); + + return buf; +} + +const std::string TrexRpcServer::s_server_uptime = get_current_date_time(); + TrexRpcServer::TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg) { /* add the request response server */ -- cgit 1.2.3-korg From 6ec401381b4b3e6facce5c9a749bc08b8c30f1a7 Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 18 Aug 2015 17:00:00 +0300 Subject: draft --- scripts/trex_console | 2 ++ src/console/trex_console.py | 3 ++- src/console/trex_rpc_client.py | 24 +++++++++++++++++------- src/console/trex_status.py | 13 ++++++++----- src/rpc-server/src/trex_rpc_server.cpp | 2 +- 5 files changed, 30 insertions(+), 14 deletions(-) create mode 100755 scripts/trex_console (limited to 'src/console/trex_rpc_client.py') diff --git a/scripts/trex_console b/scripts/trex_console new file mode 100755 index 00000000..6a79d54a --- /dev/null +++ b/scripts/trex_console @@ -0,0 +1,2 @@ +#!/bin/bash +/usr/bin/python ../src/console/trex_console.py diff --git a/src/console/trex_console.py b/src/console/trex_console.py index ca4c7e86..15022e06 100755 --- a/src/console/trex_console.py +++ b/src/console/trex_console.py @@ -15,6 +15,7 @@ class TrexConsole(cmd.Cmd): self.intro = "\n-=TRex Console V1.0=-\n" self.rpc_client = rpc_client self.verbose = False + rc, msg = self.rpc_client.query_rpc_server() if rc: @@ -96,7 +97,7 @@ class TrexConsole(cmd.Cmd): def main (): # RPC client try: - rpc_client = RpcClient(5050) + rpc_client = RpcClient("localhost", 5050) rpc_client.connect() except Exception as e: print "\n*** " + str(e) + "\n" diff --git a/src/console/trex_rpc_client.py b/src/console/trex_rpc_client.py index 04dd7727..4562cf23 100644 --- a/src/console/trex_rpc_client.py +++ b/src/console/trex_rpc_client.py @@ -5,6 +5,23 @@ from time import sleep class RpcClient(): + def __init__ (self, server, port): + self.context = zmq.Context() + + self.port = port + self.server = server + # Socket to talk to server + self.transport = "tcp://{0}:{1}".format(server, port) + + self.verbose = False + + def get_connection_details (self): + rc = {} + rc['server'] = self.server + rc['port'] = self.port + + return rc + def create_jsonrpc_v2 (self, method_name, params = {}, id = None): msg = {} msg["jsonrpc"] = "2.0" @@ -79,13 +96,6 @@ class RpcClient(): def query_rpc_server (self): return self.invoke_rpc_method("rpc_get_reg_cmds") - def __init__ (self, port): - self.context = zmq.Context() - - # Socket to talk to server - self.transport = "tcp://localhost:{0}".format(port) - - self.verbose = False def set_verbose (self, mode): self.verbose = mode diff --git a/src/console/trex_status.py b/src/console/trex_status.py index a17c2589..20d70534 100755 --- a/src/console/trex_status.py +++ b/src/console/trex_status.py @@ -91,11 +91,14 @@ class TrexStatus(): self.info_panel.clear() - self.info_panel.getwin().addstr(3, 2, "{:<30} {:30}".format("Version:", self.server_status["general"]["version"])) - self.info_panel.getwin().addstr(4, 2, "{:<30} {:30}".format("Build:", + connection_details = self.rpc_client.get_connection_details() + + self.info_panel.getwin().addstr(3, 2, "{:<30} {:30}".format("Server:", connection_details['server'] + ":" + str(connection_details['port']))) + self.info_panel.getwin().addstr(4, 2, "{:<30} {:30}".format("Version:", self.server_status["general"]["version"])) + self.info_panel.getwin().addstr(5, 2, "{:<30} {:30}".format("Build:", self.server_status["general"]["build_date"] + " @ " + self.server_status["general"]["build_time"] + " by " + self.server_status["general"]["version_user"])) - self.info_panel.getwin().addstr(5, 2, "{:<30} {:30}".format("Server Uptime:", self.server_status["general"]["uptime"])) + self.info_panel.getwin().addstr(6, 2, "{:<30} {:30}".format("Server Uptime:", self.server_status["general"]["uptime"])) #self.ft_panel.clear() #ft_section_y = 3 @@ -250,7 +253,7 @@ class TrexStatus(): self.add_log_event("Pinging RPC server") rc, msg = self.rpc_client.ping_rpc_server() if rc: - self.add_log_event("Server replied") + self.add_log_event("Server replied: '{0}'".format(msg)) else: self.add_log_event("Failed to get reply") @@ -268,7 +271,7 @@ class TrexStatus(): panel.update_panels(); self.stdscr.refresh() - sleep(0.2) + sleep(0.1) def show_trex_status_internal (stdscr, rpc_client): diff --git a/src/rpc-server/src/trex_rpc_server.cpp b/src/rpc-server/src/trex_rpc_server.cpp index 17eeec6d..139614e5 100644 --- a/src/rpc-server/src/trex_rpc_server.cpp +++ b/src/rpc-server/src/trex_rpc_server.cpp @@ -75,7 +75,7 @@ get_current_date_time() { struct tm tstruct; char buf[80]; tstruct = *localtime(&now); - strftime(buf, sizeof(buf), "%d-%b-%Y / %X", &tstruct); + strftime(buf, sizeof(buf), "%b %d %Y @ %X", &tstruct); return buf; } -- cgit 1.2.3-korg From 2acb002ded9dd522af059f3d80f3f26a4e70c1d4 Mon Sep 17 00:00:00 2001 From: imarom Date: Wed, 19 Aug 2015 13:12:10 +0300 Subject: draft --- .gitignore | 1 + linux/ws_main.py | 67 ++++++++-- src/console/trex_console.py | 36 +++--- src/console/trex_rpc_client.py | 4 +- src/console/trex_status.py | 183 ++++++++-------------------- src/main.cpp | 4 +- src/rpc-server/src/trex_rpc_server_mock.cpp | 60 +++++++++ 7 files changed, 192 insertions(+), 163 deletions(-) create mode 100644 src/rpc-server/src/trex_rpc_server_mock.cpp (limited to 'src/console/trex_rpc_client.py') diff --git a/.gitignore b/.gitignore index 26668730..71cce64e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ linux_dpdk* linux* scripts/_t-rex-* scripts/bp-sim-* +scripts/mock-* *.pyc diff --git a/linux/ws_main.py b/linux/ws_main.py index b6e4fcc2..37051ebe 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -111,6 +111,7 @@ main_src = SrcGroup(dir='src', 'msg_manager.cpp', 'gtest/tuple_gen_test.cpp', 'gtest/nat_test.cpp', + 'gtest/rpc_test.cpp', 'pal/linux/pal_utl.cpp', 'pal/linux/mbuf.cpp' @@ -138,11 +139,35 @@ net_src = SrcGroup(dir='src/common/Network/Packet', 'MacAddress.cpp', 'VLANHeader.cpp']); +# RPC code +rpc_server_src = SrcGroup(dir='src/rpc-server/src', + src_list=[ + 'trex_rpc_server.cpp', + 'trex_rpc_req_resp_server.cpp', + 'trex_rpc_jsonrpc_v2_parser.cpp', + 'trex_rpc_cmds_table.cpp', + + 'commands/trex_rpc_cmd_test.cpp', + 'commands/trex_rpc_cmd_general.cpp', + + ]) + +# RPC mock server (test) +rpc_server_mock_src = SrcGroup(dir='src/rpc-server/src', + src_list=[ + 'trex_rpc_server_mock.cpp' + ]) + # JSON package json_src = SrcGroup(dir='external_libs/json', - src_list=[ - 'jsoncpp.cpp' - ]) + src_list=[ + 'jsoncpp.cpp' + ]) + +rpc_server_mock = SrcGroups([rpc_server_src, + rpc_server_mock_src, + json_src + ]) yaml_src = SrcGroup(dir='yaml-cpp/src/', src_list=[ @@ -178,6 +203,7 @@ bp =SrcGroups([ main_src, cmn_src , net_src , + rpc_server_src, yaml_src, json_src ]); @@ -196,7 +222,10 @@ cxxflags_base =['-DWIN_UCODE_SIM', includes_path =''' ../src/pal/linux/ + ../src/zmq/include/ ../src/ + ../src/rpc-server/include + ../external_libs/json/ ../yaml-cpp/include/ '''; @@ -212,10 +241,12 @@ PLATFORM_32 = "32" class build_option: - def __init__(self,platform,debug_mode,is_pie): + def __init__(self, name, src, platform, debug_mode, is_pie): self.mode = debug_mode; ##debug,release self.platform = platform; #['32','64'] self.is_pie = is_pie + self.name = name + self.src = src def __str__(self): s=self.mode+","+self.platform; @@ -283,11 +314,14 @@ class build_option: return result; def get_target (self): - return self.update_executable_name("bp-sim"); + return self.update_executable_name(self.name); def get_flags (self): return self.cxxcomp_flags(cxxflags_base); + def get_src (self): + return self.src.file_list(top) + def get_link_flags(self): # add here basic flags base_flags = ['-lpthread']; @@ -307,25 +341,28 @@ class build_option: return base_flags; - def get_exe (self,full_path = True): - return self.toExe(self.get_target(),full_path); - build_types = [ - build_option(debug_mode= DEBUG_, platform = PLATFORM_32, is_pie = False), - build_option(debug_mode= DEBUG_, platform = PLATFORM_64, is_pie = False), - build_option(debug_mode= RELEASE_,platform = PLATFORM_32, is_pie = False), - build_option(debug_mode= RELEASE_,platform = PLATFORM_64, is_pie = False), + build_option(name = "bp-sim", src = bp, debug_mode= DEBUG_, platform = PLATFORM_32, is_pie = False), + build_option(name = "bp-sim", src = bp, debug_mode= DEBUG_, platform = PLATFORM_64, is_pie = False), + build_option(name = "bp-sim", src = bp, debug_mode= RELEASE_,platform = PLATFORM_32, is_pie = False), + build_option(name = "bp-sim", src = bp, debug_mode= RELEASE_,platform = PLATFORM_64, is_pie = False), + + build_option(name = "mock-rpc-server", src = rpc_server_mock, debug_mode= DEBUG_,platform = PLATFORM_64, is_pie = False), ] def build_prog (bld, build_obj): + zmq_lib_path='src/zmq/' + bld.read_shlib( name='zmq' , paths=[top + zmq_lib_path] ) + bld.program(features='cxx cxxprogram', includes =includes_path, cxxflags =build_obj.get_flags(), linkflags = build_obj.get_link_flags(), - source = bp.file_list(top), + source = build_obj.get_src(), + use = ['zmq'], rpath = bld.env.RPATH, target = build_obj.get_target()) @@ -336,15 +373,19 @@ def build_type(bld,build_obj): def post_build(bld): print "copy objects" + exec_p ="../scripts/" + for obj in build_types: install_single_system(bld, exec_p, obj); def build(bld): + bld.add_post_fun(post_build); for obj in build_types: build_type(bld,obj); + def build_info(bld): pass; diff --git a/src/console/trex_console.py b/src/console/trex_console.py index 15022e06..584089ae 100755 --- a/src/console/trex_console.py +++ b/src/console/trex_console.py @@ -12,10 +12,14 @@ class TrexConsole(cmd.Cmd): def __init__(self, rpc_client): cmd.Cmd.__init__(self) self.prompt = "TRex > " - self.intro = "\n-=TRex Console V1.0=-\n" + + self.intro = "\n-=TRex Console V1.0=-\n" + self.intro += "\nType 'help' or '?' for supported actions\n" + self.rpc_client = rpc_client self.verbose = False + # before starting query the RPC server and add the methods rc, msg = self.rpc_client.query_rpc_server() if rc: @@ -29,20 +33,22 @@ class TrexConsole(cmd.Cmd): # set verbose on / off def do_verbose (self, line): - '''shows or set verbose mode\nusage: verbose [on/off]\n''' + '''\nshows or set verbose mode\nusage: verbose [on/off]\n''' if line == "": - print "verbose is " + ("on" if self.verbose else "off") + print "\nverbose is " + ("on\n" if self.verbose else "off\n") + elif line == "on": self.verbose = True self.rpc_client.set_verbose(True) - print "verbose set to on\n" + print "\nverbose set to on\n" elif line == "off": self.verbose = False self.rpc_client.set_verbose(False) - print "verbose set to off\n" + print "\nverbose set to off\n" + else: - print "please specify 'on' or 'off'\n" + print "\nplease specify 'on' or 'off'\n" # query the server for registered commands def do_query_server(self, line): @@ -51,11 +57,11 @@ class TrexConsole(cmd.Cmd): if not rc: print "\n*** Failed to query RPC server: " + str(msg) - print "RPC server supports the following commands: \n\n" + msg + print "\nRPC server supports the following commands: \n\n" + msg def do_ping (self, line): - '''pings the RPC server\n''' - print "Pinging RPC server" + '''\npings the RPC server\n''' + print "\n-> Pinging RPC server" rc, msg = self.rpc_client.ping_rpc_server() if rc: @@ -64,9 +70,9 @@ class TrexConsole(cmd.Cmd): print "[FAILED]\n" def do_rpc (self, line): - '''Launches a RPC on the server\n''' + '''\nLaunches a RPC on the server\n''' if line == "": - print "Please provide method name\n" + print "\nUsage: [method name] [param 1] ...\n" return rc, msg = self.rpc_client.invoke_rpc_method(line) @@ -81,7 +87,9 @@ class TrexConsole(cmd.Cmd): return [x for x in self.supported_rpc if x.startswith(text)] def do_status (self, line): - '''Shows a graphical console\n''' + '''\nShows a graphical console\n''' + + self.do_verbose('off') trex_status.show_trex_status(self.rpc_client) def do_quit(self, line): @@ -89,10 +97,10 @@ class TrexConsole(cmd.Cmd): return True def default(self, line): - print "'{0}' is an unrecognized command\n".format(line) + print "'{0}' is an unrecognized command. type 'help' or '?' for a list\n".format(line) # aliasing - do_EOF = do_q = do_quit + do_exit = do_EOF = do_q = do_quit def main (): # RPC client diff --git a/src/console/trex_rpc_client.py b/src/console/trex_rpc_client.py index 4562cf23..fe8f69a2 100644 --- a/src/console/trex_rpc_client.py +++ b/src/console/trex_rpc_client.py @@ -39,7 +39,7 @@ class RpcClient(): msg = self.create_jsonrpc_v2(method_name, params, id = 1) if self.verbose: - print "\nSending Request To Server: " + str(msg) + "\n" + print "\n[verbose] Sending Request To Server: " + str(msg) + "\n" if block: self.socket.send(msg) @@ -67,7 +67,7 @@ class RpcClient(): return False, "Failed To Get Server Response" if self.verbose: - print "Server Response: " + str(response) + "\n" + print "[verbose] Server Response: " + str(response) # decode response_json = json.loads(response) diff --git a/src/console/trex_status.py b/src/console/trex_status.py index 20d70534..8ee669b5 100755 --- a/src/console/trex_status.py +++ b/src/console/trex_status.py @@ -85,6 +85,7 @@ class TrexStatus(): return win, panel1 + # static info panel def update_info (self): if self.server_status == None: return @@ -99,106 +100,12 @@ class TrexStatus(): self.server_status["general"]["build_date"] + " @ " + self.server_status["general"]["build_time"] + " by " + self.server_status["general"]["version_user"])) self.info_panel.getwin().addstr(6, 2, "{:<30} {:30}".format("Server Uptime:", self.server_status["general"]["uptime"])) - #self.ft_panel.clear() - - #ft_section_y = 3 - #self.ft_panel.getwin().addstr(ft_section_y, 2,"General Info:", curses.A_UNDERLINE) - - #self.ft_panel.getwin().addstr(ft_section_y, 2, "{:<30} {:<30,}".format("Total Flows Opened:", ft_stats["total-opened-flows"])) - #ft_section_y = ft_section_y + 1 - #self.ft_panel.getwin().addstr(ft_section_y, 2, "{:<30} {:<30,}".format("Total Flows Closed:", ft_stats["total-closed-flows"])) - #ft_section_y = ft_section_y + 1 - #self.ft_panel.getwin().addstr(ft_section_y, 2, "{:<30} {:<30,}".format("Current Active Flows:", ft_stats["active-flows"])) - #ft_section_y = ft_section_y + 1 - #self.ft_panel.getwin().addstr(ft_section_y, 2, "{:<30} {:<30,}".format("Flow Allocation Errors:", ft_stats["allocation_err"])) + # general stats def update_general (self, gen_stats): + pass - if not gen_stats: - return - - transport_info_section_y = 3 - general_info_section_y = int(self.cls_panel.h * 0.5) - - self.general_panel.clear() - - # transport layer info - self.general_panel.getwin().addstr(transport_info_section_y, 2, "{:<30} {:^10} {:^5} {:^10}".format("Total Tx Rate:", - float_to_human_readable(gen_stats["total-rx-bps"]), - "/", - float_to_human_readable(gen_stats["total-rx-pps"], suffix = "pps"))) - transport_info_section_y += 2 - - - self.general_panel.getwin().addstr(transport_info_section_y, 2, "{:<30} {:^6.2f} %".format("DP Core Util.:", gen_stats["cpu-util"])); - - transport_info_section_y += 2 - - for i in range(1, 3): - self.general_panel.getwin().addstr(transport_info_section_y, 2, "{:<30} {:^10} {:^5} {:^10}".format("Port {0} Rx:".format(i), - float_to_human_readable(gen_stats["port " + str(i)]["total-rx-bps"]), - "/", - float_to_human_readable(gen_stats["port " + str(i)]["total-rx-pps"], suffix = "pps"))) - transport_info_section_y += 1 - - - self.general_panel.getwin().addstr(general_info_section_y, 2,"General Info:", curses.A_UNDERLINE) - general_info_section_y = general_info_section_y + 2 - - self.general_panel.getwin().addstr(general_info_section_y, 2, "{:<30} {:<30}".format("VNBAR Main Process PID:", os.getppid())) - general_info_section_y = general_info_section_y + 1 - self.general_panel.getwin().addstr(general_info_section_y, 2, "{:<30} {:<30}".format("ZMQ client online at:", vnbar_ipc.VnbarIpc.get_zmq_transport_name())) - - - # v2 - def update_cls (self, pd_stats): - if not pd_stats: - return - - self.cls_panel.clear() - - section_start = 3 - section_size = (self.cls_panel.h / 2) - 5 - - for port_name, pd in sorted(pd_stats.iteritems()): - if pd == None: - continue - - # sort by bandwidth - pd = collections.OrderedDict(sorted(pd.items(), key=operator.itemgetter(1), reverse = True)) - - # restart the line index - line_index = 0 - - # headline - self.cls_panel.getwin().addstr(section_start + line_index, 2, "{0}:".format(port_name), curses.A_BOLD | curses.A_UNDERLINE) - line_index += 1 - - cls_str = "{:^45} {:^20} {:^20} {:^20}".format("Protocol Name", "Byte Count", "Packet Count", "B/W Perc.") - self.cls_panel.getwin().addstr(section_start + line_index, 2, cls_str) - line_index += 2 - - # protocols - proto_index = 0 - proto_count = len(pd) - - total_bandwidth = sum([i['bytes'] for i in pd.values()]) - - for proto_name, cnts in pd.iteritems(): - proto_str = "{:<45} {:^20,} {:^20,} {:^20}".format(proto_name, cnts['bytes'], cnts['pkts'], percentage(cnts['bytes'], total_bandwidth) ) - proto_index = proto_index + 1 - - if line_index > section_size: - self.cls_panel.getwin().addstr(section_start + line_index, 2, "<...{0} More...>".format(proto_count - proto_index), (curses.A_DIM if ((line_index % 2) == 0) else curses.A_BOLD)) - break - - self.cls_panel.getwin().addstr(section_start + line_index, 2, proto_str, (curses.A_DIM if ((line_index % 2) == 0) else curses.A_BOLD)) - - line_index += 1 - - section_start = section_start + section_size + 3 - - + # control panel def update_control (self): self.control_panel.clear() @@ -214,17 +121,7 @@ class TrexStatus(): self.control_panel.getwin().addstr(index, 2, l) index += 1 - def run (self): - try: - curses.curs_set(0) - except: - pass - - curses.use_default_colors() - self.stdscr.nodelay(1) - curses.nonl() - curses.noecho() - + def generate_layout (self): self.max_y = self.stdscr.getmaxyx()[0] self.max_x = self.stdscr.getmaxyx()[1] @@ -239,32 +136,54 @@ class TrexStatus(): panel.update_panels(); self.stdscr.refresh() + def wait_for_key_input (self): + ch = self.stdscr.getch() + + if (ch != curses.ERR): + # stop/start status + if (ch == ord('f')): + self.update_active = not self.update_active + self.add_log_event("Update continued" if self.update_active else "Update stopped") + + elif (ch == ord('p')): + self.add_log_event("Pinging RPC server") + rc, msg = self.rpc_client.ping_rpc_server() + if rc: + self.add_log_event("Server replied: '{0}'".format(msg)) + else: + self.add_log_event("Failed to get reply") + + # c - clear stats + elif (ch == ord('c')): + self.add_log_event("Statistics cleared") + + elif (ch == ord('q')): + return False + else: + self.add_log_event("Unknown key pressed {0}".format("'" + chr(ch) + "'" if chr(ch).isalpha() else "")) + + return True + + # main run entry point + def run (self): + try: + curses.curs_set(0) + except: + pass + + curses.use_default_colors() + self.stdscr.nodelay(1) + curses.nonl() + curses.noecho() + + self.generate_layout() + self.update_active = True while (True): - ch = self.stdscr.getch() - - if (ch != curses.ERR): - # stop/start status - if (ch == ord('f')): - self.update_active = not self.update_active - self.add_log_event("Update continued" if self.update_active else "Update stopped") - - elif (ch == ord('p')): - self.add_log_event("Pinging RPC server") - rc, msg = self.rpc_client.ping_rpc_server() - if rc: - self.add_log_event("Server replied: '{0}'".format(msg)) - else: - self.add_log_event("Failed to get reply") - - # c - clear stats - elif (ch == ord('c')): - self.add_log_event("Statistics cleared") - - elif (ch == ord('q')): - break - else: - self.add_log_event("Unknown key pressed {0}".format("'" + chr(ch) + "'" if chr(ch).isalpha() else "")) + + rc = self.wait_for_key_input() + if not rc: + break self.update_control() self.update_info() diff --git a/src/main.cpp b/src/main.cpp index e3176be3..ddcf81e2 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,11 +32,11 @@ limitations under the License. * (improved stub) * */ -extern "C" char * get_build_date(void){ +extern "C" const char * get_build_date(void){ return (__DATE__); } -extern "C" char * get_build_time(void){ +extern "C" const char * get_build_time(void){ return (__TIME__ ); } diff --git a/src/rpc-server/src/trex_rpc_server_mock.cpp b/src/rpc-server/src/trex_rpc_server_mock.cpp new file mode 100644 index 00000000..3c63f74a --- /dev/null +++ b/src/rpc-server/src/trex_rpc_server_mock.cpp @@ -0,0 +1,60 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include + +using namespace std; + +/** + * on simulation this is not rebuild every version + * (improved stub) + * + */ +extern "C" const char * get_build_date(void){ + return (__DATE__); +} + +extern "C" const char * get_build_time(void){ + return (__TIME__ ); +} + +int main() { + cout << "\n-= Starting RPC Server Mock =-\n\n"; + cout << "Listening on tcp://localhost:5050 [ZMQ]\n\n"; + + TrexRpcServerConfig rpc_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5050); + TrexRpcServer rpc(rpc_cfg); + + /* init the RPC server */ + rpc.start(); + + cout << "Server Started\n\n"; + + while (true) { + sleep(1); + } + + rpc.stop(); + + +} -- cgit 1.2.3-korg From da56afe25e71f4dc65ae4669889eec5b8fc43afc Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 20 Aug 2015 10:36:53 +0300 Subject: draft --- src/console/trex_console.py | 19 +++++----- src/console/trex_rpc_client.py | 27 ++++++++++---- src/rpc-server/include/trex_rpc_server_api.h | 44 ++++++++++++++++++++--- src/rpc-server/src/commands/trex_rpc_cmd_test.cpp | 8 +++-- src/rpc-server/src/trex_rpc_req_resp_server.cpp | 15 +++++--- src/rpc-server/src/trex_rpc_server.cpp | 33 ++++++++++++++++- src/rpc-server/src/trex_rpc_server_mock.cpp | 3 ++ 7 files changed, 119 insertions(+), 30 deletions(-) (limited to 'src/console/trex_rpc_client.py') diff --git a/src/console/trex_console.py b/src/console/trex_console.py index 584089ae..be84640c 100755 --- a/src/console/trex_console.py +++ b/src/console/trex_console.py @@ -23,8 +23,7 @@ class TrexConsole(cmd.Cmd): rc, msg = self.rpc_client.query_rpc_server() if rc: - lst = msg.split('\n') - self.supported_rpc = [str(x) for x in lst if x] + self.supported_rpc = [str(x) for x in msg if x] # a cool hack - i stole this function and added space def completenames(self, text, *ignored): @@ -57,7 +56,11 @@ class TrexConsole(cmd.Cmd): if not rc: print "\n*** Failed to query RPC server: " + str(msg) - print "\nRPC server supports the following commands: \n\n" + msg + print "\nRPC server supports the following commands: \n\n" + for func in msg: + if func: + print func + print "\n" def do_ping (self, line): '''\npings the RPC server\n''' @@ -81,7 +84,6 @@ class TrexConsole(cmd.Cmd): else: print "[FAILED]\n" - print "Server Response:\n\n{0}\n".format(json.dumps(msg)) def complete_rpc (self, text, line, begidx, endidx): return [x for x in self.supported_rpc if x.startswith(text)] @@ -104,11 +106,10 @@ class TrexConsole(cmd.Cmd): def main (): # RPC client - try: - rpc_client = RpcClient("localhost", 5050) - rpc_client.connect() - except Exception as e: - print "\n*** " + str(e) + "\n" + rpc_client = RpcClient("localhost", 5050) + rc, msg = rpc_client.connect() + if not rc: + print "\n*** " + msg + "\n" exit(-1) # console diff --git a/src/console/trex_rpc_client.py b/src/console/trex_rpc_client.py index fe8f69a2..f3edd252 100644 --- a/src/console/trex_rpc_client.py +++ b/src/console/trex_rpc_client.py @@ -2,6 +2,7 @@ import zmq import json from time import sleep +import random class RpcClient(): @@ -22,6 +23,16 @@ class RpcClient(): return rc + def pretty_json (self, json_str): + return json.dumps(json.loads(json_str), indent = 4, separators=(',', ': ')) + + def verbose_msg (self, msg): + if not self.verbose: + return + + print "[verbose] " + msg + + def create_jsonrpc_v2 (self, method_name, params = {}, id = None): msg = {} msg["jsonrpc"] = "2.0" @@ -36,10 +47,10 @@ class RpcClient(): return json.dumps(msg) def invoke_rpc_method (self, method_name, params = {}, block = True): - msg = self.create_jsonrpc_v2(method_name, params, id = 1) + id = random.randint(1, 1000) + msg = self.create_jsonrpc_v2(method_name, params, id = id) - if self.verbose: - print "\n[verbose] Sending Request To Server: " + str(msg) + "\n" + self.verbose_msg("Sending Request To Server:\n\n" + self.pretty_json(msg) + "\n") if block: self.socket.send(msg) @@ -66,8 +77,7 @@ class RpcClient(): if not got_response: return False, "Failed To Get Server Response" - if self.verbose: - print "[verbose] Server Response: " + str(response) + self.verbose_msg("Server Response:\n\n" + self.pretty_json(response) + "\n") # decode response_json = json.loads(response) @@ -75,6 +85,9 @@ class RpcClient(): if (response_json.get("jsonrpc") != "2.0"): return False, "Malfromed Response ({0})".format(str(response)) + if (response_json.get("id") != id): + return False, "Server Replied With Bad ID ({0})".format(str(response)) + # error reported by server if ("error" in response_json): return False, response_json["error"]["message"] @@ -111,11 +124,11 @@ class RpcClient(): rc, err = self.ping_rpc_server() if not rc: self.context.destroy(linger = 0) - raise Exception(err) + return False, err #print "Connection Established !\n" print "[SUCCESS]\n" - + return True, "" def __del__ (self): print "Shutting down RPC client\n" diff --git a/src/rpc-server/include/trex_rpc_server_api.h b/src/rpc-server/include/trex_rpc_server_api.h index bb455be2..6bb81c73 100644 --- a/src/rpc-server/include/trex_rpc_server_api.h +++ b/src/rpc-server/include/trex_rpc_server_api.h @@ -68,7 +68,7 @@ private: class TrexRpcServerInterface { public: - TrexRpcServerInterface(const TrexRpcServerConfig &cfg); + TrexRpcServerInterface(const TrexRpcServerConfig &cfg, const std::string &name); virtual ~TrexRpcServerInterface(); /** @@ -83,23 +83,43 @@ public: */ void stop(); + /** + * set verbose on or off + * + */ + void set_verbose(bool verbose); + /** * return TRUE if server is active * */ bool is_running(); + /** + * is the server verbose or not + * + */ + bool is_verbose(); + protected: /** * instances implement this * */ - virtual void _rpc_thread_cb() = 0; - virtual void _stop_rpc_thread() = 0; + virtual void _rpc_thread_cb() = 0; + virtual void _stop_rpc_thread() = 0; + + /** + * prints a verbosed message (if enabled) + * + */ + void verbose_msg(const std::string &msg); TrexRpcServerConfig m_cfg; bool m_is_running; + bool m_is_verbose; std::thread *m_thread; + std::string m_name; }; /** @@ -116,16 +136,30 @@ public: TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg); ~TrexRpcServer(); + /** + * starts the RPC server + * + * @author imarom (19-Aug-15) + */ void start(); + + /** + * stops the RPC server + * + * @author imarom (19-Aug-15) + */ void stop(); + void set_verbose(bool verbose); + static const std::string &get_server_uptime() { return s_server_uptime; } private: - std::vector m_servers; - static const std::string s_server_uptime; + std::vector m_servers; + bool m_verbose; + static const std::string s_server_uptime; }; #endif /* __TREX_RPC_SERVER_API_H__ */ diff --git a/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp b/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp index f2d4121e..e9cc4665 100644 --- a/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp +++ b/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp @@ -95,7 +95,6 @@ TrexRpcCmdPing::_run(const Json::Value ¶ms, Json::Value &result) { TrexRpcCommand::rpc_cmd_rc_e TrexRpcCmdGetReg::_run(const Json::Value ¶ms, Json::Value &result) { vector cmds; - stringstream ss; /* validate count */ if (params.size() != 0) { @@ -104,11 +103,14 @@ TrexRpcCmdGetReg::_run(const Json::Value ¶ms, Json::Value &result) { TrexRpcCommandsTable::get_instance().query(cmds); + + Json::Value test = Json::arrayValue; for (auto cmd : cmds) { - ss << cmd << "\n"; + test.append(cmd); } - result["result"] = ss.str(); + result["result"] = test; + return (RPC_CMD_OK); } diff --git a/src/rpc-server/src/trex_rpc_req_resp_server.cpp b/src/rpc-server/src/trex_rpc_req_resp_server.cpp index e40f5554..7484758d 100644 --- a/src/rpc-server/src/trex_rpc_req_resp_server.cpp +++ b/src/rpc-server/src/trex_rpc_req_resp_server.cpp @@ -34,7 +34,7 @@ limitations under the License. * ZMQ based request-response server * */ -TrexRpcServerReqRes::TrexRpcServerReqRes(const TrexRpcServerConfig &cfg) : TrexRpcServerInterface(cfg) { +TrexRpcServerReqRes::TrexRpcServerReqRes(const TrexRpcServerConfig &cfg) : TrexRpcServerInterface(cfg, "req resp") { /* ZMQ is not thread safe - this should be outside */ m_context = zmq_ctx_new(); } @@ -84,6 +84,9 @@ void TrexRpcServerReqRes::_rpc_thread_cb() { /* transform it to a string */ std::string request((const char *)m_msg_buffer, msg_size); + + verbose_msg("Server Received: " + request); + handle_request(request); } @@ -128,14 +131,16 @@ void TrexRpcServerReqRes::handle_request(const std::string &request) { } /* write the JSON to string and sever on ZMQ */ - std::string reponse_str; + std::string response_str; if (response.size() == 1) { - reponse_str = writer.write(response[0]); + response_str = writer.write(response[0]); } else { - reponse_str = writer.write(response); + response_str = writer.write(response); } - zmq_send(m_socket, reponse_str.c_str(), reponse_str.size(), 0); + verbose_msg("Server Replied: " + response_str); + + zmq_send(m_socket, response_str.c_str(), response_str.size(), 0); } diff --git a/src/rpc-server/src/trex_rpc_server.cpp b/src/rpc-server/src/trex_rpc_server.cpp index 139614e5..366bfc5b 100644 --- a/src/rpc-server/src/trex_rpc_server.cpp +++ b/src/rpc-server/src/trex_rpc_server.cpp @@ -24,11 +24,13 @@ limitations under the License. #include #include #include +#include /************** RPC server interface ***************/ -TrexRpcServerInterface::TrexRpcServerInterface(const TrexRpcServerConfig &cfg) : m_cfg(cfg) { +TrexRpcServerInterface::TrexRpcServerInterface(const TrexRpcServerConfig &cfg, const std::string &name) : m_cfg(cfg), m_name(name) { m_is_running = false; + m_is_verbose = false; } TrexRpcServerInterface::~TrexRpcServerInterface() { @@ -37,6 +39,14 @@ TrexRpcServerInterface::~TrexRpcServerInterface() { } } +void TrexRpcServerInterface::verbose_msg(const std::string &msg) { + if (!m_is_verbose) { + return; + } + + std::cout << "[verbose][" << m_name << "] " << msg << "\n"; +} + /** * starts a RPC specific server * @@ -45,6 +55,8 @@ TrexRpcServerInterface::~TrexRpcServerInterface() { void TrexRpcServerInterface::start() { m_is_running = true; + verbose_msg("Starting RPC Server"); + m_thread = new std::thread(&TrexRpcServerInterface::_rpc_thread_cb, this); if (!m_thread) { throw TrexRpcException("unable to create RPC thread"); @@ -54,14 +66,27 @@ void TrexRpcServerInterface::start() { void TrexRpcServerInterface::stop() { m_is_running = false; + verbose_msg("Attempting To Stop RPC Server"); + /* call the dynamic type class stop */ _stop_rpc_thread(); /* hold until thread has joined */ m_thread->join(); + + verbose_msg("Server Stopped"); + delete m_thread; } +void TrexRpcServerInterface::set_verbose(bool verbose) { + m_is_verbose = verbose; +} + +bool TrexRpcServerInterface::is_verbose() { + return m_is_verbose; +} + bool TrexRpcServerInterface::is_running() { return m_is_running; } @@ -120,3 +145,9 @@ void TrexRpcServer::stop() { } } +void TrexRpcServer::set_verbose(bool verbose) { + for (auto server : m_servers) { + server->set_verbose(verbose); + } +} + diff --git a/src/rpc-server/src/trex_rpc_server_mock.cpp b/src/rpc-server/src/trex_rpc_server_mock.cpp index b01fff90..fd4f051c 100644 --- a/src/rpc-server/src/trex_rpc_server_mock.cpp +++ b/src/rpc-server/src/trex_rpc_server_mock.cpp @@ -60,6 +60,9 @@ int main(int argc, char *argv[]) { /* init the RPC server */ rpc.start(); + cout << "Setting Server To Full Verbose\n\n"; + rpc.set_verbose(true); + cout << "Server Started\n\n"; while (true) { -- cgit 1.2.3-korg From a6be0ea727a21e24e1efb77eaf55893a545de233 Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 20 Aug 2015 13:51:31 +0300 Subject: added support for paramters in the python console --- src/console/trex_console.py | 27 +++++++++++++++++++++-- src/console/trex_rpc_client.py | 12 +++++----- src/rpc-server/include/trex_rpc_cmd_api.h | 14 ++++++++++++ src/rpc-server/src/commands/trex_rpc_cmd_test.cpp | 12 +++++++++- src/rpc-server/src/commands/trex_rpc_cmds.h | 10 ++++----- src/rpc-server/src/trex_rpc_jsonrpc_v2_parser.cpp | 10 +++++---- 6 files changed, 66 insertions(+), 19 deletions(-) (limited to 'src/console/trex_rpc_client.py') diff --git a/src/console/trex_console.py b/src/console/trex_console.py index be84640c..b4048f5b 100755 --- a/src/console/trex_console.py +++ b/src/console/trex_console.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- import cmd import json +import ast from trex_rpc_client import RpcClient import trex_status @@ -75,10 +76,32 @@ class TrexConsole(cmd.Cmd): def do_rpc (self, line): '''\nLaunches a RPC on the server\n''' if line == "": - print "\nUsage: [method name] [param 1] ...\n" + print "\nUsage: [method name] [param dict as string]\n" return - rc, msg = self.rpc_client.invoke_rpc_method(line) + 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" + return + + rc, msg = self.rpc_client.invoke_rpc_method(method, params) if rc: print "[SUCCESS]\n" else: diff --git a/src/console/trex_rpc_client.py b/src/console/trex_rpc_client.py index f3edd252..3ec0e1f6 100644 --- a/src/console/trex_rpc_client.py +++ b/src/console/trex_rpc_client.py @@ -24,7 +24,7 @@ class RpcClient(): return rc def pretty_json (self, json_str): - return json.dumps(json.loads(json_str), indent = 4, separators=(',', ': ')) + return json.dumps(json.loads(json_str), indent = 4, separators=(',', ': '), sort_keys = True) def verbose_msg (self, msg): if not self.verbose: @@ -38,9 +38,7 @@ class RpcClient(): msg["jsonrpc"] = "2.0" msg["method"] = method_name - msg["params"] = {} - for key, value in params.iteritems(): - msg["params"][key] = value + msg["params"] = params msg["id"] = id @@ -101,13 +99,13 @@ class RpcClient(): def ping_rpc_server (self): - return self.invoke_rpc_method("rpc_ping", block = False) + return self.invoke_rpc_method("ping", block = False) def get_rpc_server_status (self): - return self.invoke_rpc_method("rpc_get_status") + return self.invoke_rpc_method("get_status") def query_rpc_server (self): - return self.invoke_rpc_method("rpc_get_reg_cmds") + return self.invoke_rpc_method("get_reg_cmds") def set_verbose (self, mode): diff --git a/src/rpc-server/include/trex_rpc_cmd_api.h b/src/rpc-server/include/trex_rpc_cmd_api.h index 308e344c..c773b15f 100644 --- a/src/rpc-server/include/trex_rpc_cmd_api.h +++ b/src/rpc-server/include/trex_rpc_cmd_api.h @@ -69,6 +69,20 @@ protected: */ virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result) = 0; + /** + * error generating functions + * + */ + void genernate_err(Json::Value &result, const std::string &msg) { + result["specific_err"] = msg; + } + + void generate_err_param_count(Json::Value &result, int expected, int provided) { + std::stringstream ss; + ss << "method expects '" << expected << "' paramteres, '" << provided << "' provided"; + genernate_err(result, ss.str()); + } + std::string m_name; }; diff --git a/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp b/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp index e9cc4665..e2dc8959 100644 --- a/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp +++ b/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp @@ -37,11 +37,18 @@ TrexRpcCmdTestAdd::_run(const Json::Value ¶ms, Json::Value &result) { /* validate count */ if (params.size() != 2) { + generate_err_param_count(result, 2, params.size()); return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR); } /* check we have all the required paramters */ - if (!x.isInt() || !y.isInt()) { + if (!x.isInt()) { + genernate_err(result, "'x' is either missing or not an integer"); + return (TrexRpcCommand::RPC_CMD_PARAM_PARSE_ERR); + } + + if (!y.isInt()) { + genernate_err(result, "'y' is either missing or not an integer"); return (TrexRpcCommand::RPC_CMD_PARAM_PARSE_ERR); } @@ -62,6 +69,7 @@ TrexRpcCmdTestSub::_run(const Json::Value ¶ms, Json::Value &result) { /* validate count */ if (params.size() != 2) { + generate_err_param_count(result, 2, params.size()); return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR); } @@ -82,6 +90,7 @@ TrexRpcCmdPing::_run(const Json::Value ¶ms, Json::Value &result) { /* validate count */ if (params.size() != 0) { + generate_err_param_count(result, 0, params.size()); return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR); } @@ -98,6 +107,7 @@ TrexRpcCmdGetReg::_run(const Json::Value ¶ms, Json::Value &result) { /* validate count */ if (params.size() != 0) { + generate_err_param_count(result, 0, params.size()); return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR); } diff --git a/src/rpc-server/src/commands/trex_rpc_cmds.h b/src/rpc-server/src/commands/trex_rpc_cmds.h index 0778b75d..e37e1cda 100644 --- a/src/rpc-server/src/commands/trex_rpc_cmds.h +++ b/src/rpc-server/src/commands/trex_rpc_cmds.h @@ -35,7 +35,7 @@ limitations under the License. */ class TrexRpcCmdTestAdd : public TrexRpcCommand { public: - TrexRpcCmdTestAdd() : TrexRpcCommand("rpc_test_add") {} + TrexRpcCmdTestAdd() : TrexRpcCommand("test_add") {} protected: virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); }; @@ -46,7 +46,7 @@ protected: */ class TrexRpcCmdTestSub : public TrexRpcCommand { public: - TrexRpcCmdTestSub() : TrexRpcCommand("rpc_test_sub") {} ; + TrexRpcCmdTestSub() : TrexRpcCommand("test_sub") {} ; protected: virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); }; @@ -57,7 +57,7 @@ protected: */ class TrexRpcCmdPing : public TrexRpcCommand { public: - TrexRpcCmdPing() : TrexRpcCommand("rpc_ping") {}; + TrexRpcCmdPing() : TrexRpcCommand("ping") {}; protected: virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); }; @@ -68,7 +68,7 @@ protected: */ class TrexRpcCmdGetReg : public TrexRpcCommand { public: - TrexRpcCmdGetReg() : TrexRpcCommand("rpc_get_reg_cmds") {}; + TrexRpcCmdGetReg() : TrexRpcCommand("get_reg_cmds") {}; protected: virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); }; @@ -79,7 +79,7 @@ protected: */ class TrexRpcCmdGetStatus : public TrexRpcCommand { public: - TrexRpcCmdGetStatus() : TrexRpcCommand("rpc_get_status") {}; + TrexRpcCmdGetStatus() : TrexRpcCommand("get_status") {}; protected: virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); }; diff --git a/src/rpc-server/src/trex_rpc_jsonrpc_v2_parser.cpp b/src/rpc-server/src/trex_rpc_jsonrpc_v2_parser.cpp index c11c603f..be1eb2f8 100644 --- a/src/rpc-server/src/trex_rpc_jsonrpc_v2_parser.cpp +++ b/src/rpc-server/src/trex_rpc_jsonrpc_v2_parser.cpp @@ -80,13 +80,15 @@ public: case TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR: case TrexRpcCommand::RPC_CMD_PARAM_PARSE_ERR: - response["error"]["code"] = JSONRPC_V2_ERR_INVALID_PARAMS; - response["error"]["message"] = "Bad paramters for method"; + response["error"]["code"] = JSONRPC_V2_ERR_INVALID_PARAMS; + response["error"]["message"] = "Bad paramters for method"; + response["error"]["specific_err"] = result["specific_err"]; break; case TrexRpcCommand::RPC_CMD_INTERNAL_ERR: - response["error"]["code"] = JSONRPC_V2_ERR_INTERNAL_ERROR; - response["error"]["message"] = "Internal Server Error"; + response["error"]["code"] = JSONRPC_V2_ERR_INTERNAL_ERROR; + response["error"]["message"] = "Internal Server Error"; + response["error"]["specific_err"] = result["specific_err"]; break; } -- cgit 1.2.3-korg From c3e34b2f9dfd3a9342bc2c773c3e5a92701a2d2c Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 20 Aug 2015 16:35:39 +0300 Subject: few python changes --- src/console/trex_console.py | 105 ++++++++++++++++++--- src/console/trex_rpc_client.py | 76 +++++++++++---- .../src/commands/trex_rpc_cmd_general.cpp | 1 + 3 files changed, 149 insertions(+), 33 deletions(-) (limited to 'src/console/trex_rpc_client.py') diff --git a/src/console/trex_console.py b/src/console/trex_console.py index b4048f5b..bd2af92a 100755 --- a/src/console/trex_console.py +++ b/src/console/trex_console.py @@ -12,7 +12,13 @@ class TrexConsole(cmd.Cmd): def __init__(self, rpc_client): cmd.Cmd.__init__(self) - self.prompt = "TRex > " + + rc, msg = rpc_client.connect() + if not rc: + print "\n*** " + msg + self.prompt = "Trex (offline) > " + else: + self.prompt = "TRex > " self.intro = "\n-=TRex Console V1.0=-\n" self.intro += "\nType 'help' or '?' for supported actions\n" @@ -33,7 +39,7 @@ class TrexConsole(cmd.Cmd): # set verbose on / off def do_verbose (self, line): - '''\nshows or set verbose mode\nusage: verbose [on/off]\n''' + '''shows or set verbose mode\n''' if line == "": print "\nverbose is " + ("on\n" if self.verbose else "off\n") @@ -52,10 +58,12 @@ class TrexConsole(cmd.Cmd): # query the server for registered commands def do_query_server(self, line): - '''\nquery the RPC server for supported remote commands\n''' + '''query the RPC server for supported remote commands\n''' + rc, msg = self.rpc_client.query_rpc_server() if not rc: - print "\n*** Failed to query RPC server: " + str(msg) + print "\n*** " + msg + "\n" + return print "\nRPC server supports the following commands: \n\n" for func in msg: @@ -64,19 +72,30 @@ class TrexConsole(cmd.Cmd): print "\n" def do_ping (self, line): - '''\npings the RPC server\n''' + '''Pings the RPC server\n''' + print "\n-> Pinging RPC server" rc, msg = self.rpc_client.ping_rpc_server() if rc: print "[SUCCESS]\n" else: - print "[FAILED]\n" + print "\n*** " + msg + "\n" + + def do_reconnect (self, line): + '''Reconnects to the server\n''' + rc, msg = self.rpc_client.reconnect() + if rc: + print "[SUCCESS]\n" + else: + print "\n*** " + msg + "\n" def do_rpc (self, line): - '''\nLaunches a RPC on the server\n''' + '''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) @@ -99,41 +118,97 @@ class TrexConsole(cmd.Cmd): 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 rc, msg = self.rpc_client.invoke_rpc_method(method, params) if rc: - print "[SUCCESS]\n" + print "\nServer Response:\n\n" + json.dumps(msg) + "\n" else: - print "[FAILED]\n" + 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): - '''\nShows a graphical console\n''' + '''Shows a graphical console\n''' self.do_verbose('off') trex_status.show_trex_status(self.rpc_client) def do_quit(self, line): - '''\nexit the client\n''' + '''exit the client\n''' return True + def do_disconnect (self, line): + '''Disconnect from the server\n''' + if not self.rpc_client.is_connected(): + print "Not connected to server\n" + return + + rc, msg = self.rpc_client.disconnect() + if rc: + print "[SUCCESS]\n" + else: + print msg + "\n" + + def postcmd(self, stop, line): + if self.rpc_client.is_connected(): + self.prompt = "TRex > " + else: + 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) + + # aliasing do_exit = do_EOF = do_q = do_quit def main (): # RPC client rpc_client = RpcClient("localhost", 5050) - rc, msg = rpc_client.connect() - if not rc: - print "\n*** " + msg + "\n" - exit(-1) # console try: diff --git a/src/console/trex_rpc_client.py b/src/console/trex_rpc_client.py index 3ec0e1f6..2ce44afb 100644 --- a/src/console/trex_rpc_client.py +++ b/src/console/trex_rpc_client.py @@ -6,15 +6,13 @@ import random class RpcClient(): - def __init__ (self, server, port): - self.context = zmq.Context() - - self.port = port - self.server = server - # Socket to talk to server - self.transport = "tcp://{0}:{1}".format(server, port) - + def __init__ (self, default_server, default_port): self.verbose = False + self.connected = False + + # default values + self.port = default_port + self.server = default_server def get_connection_details (self): rc = {} @@ -44,7 +42,17 @@ class RpcClient(): return json.dumps(msg) - def invoke_rpc_method (self, method_name, params = {}, block = True): + def invoke_rpc_method (self, method_name, params = {}, block = False): + rc, msg = self._invoke_rpc_method(method_name, params, block) + if not rc: + self.disconnect() + + return rc, msg + + def _invoke_rpc_method (self, method_name, params = {}, block = False): + if not self.connected: + return False, "Not connected to server" + id = random.randint(1, 1000) msg = self.create_jsonrpc_v2(method_name, params, id = id) @@ -56,7 +64,7 @@ class RpcClient(): try: self.socket.send(msg, flags = zmq.NOBLOCK) except zmq.error.ZMQError: - return False, "Failed To Get Server Response" + return False, "Failed To Get Send Message" got_response = False @@ -64,13 +72,13 @@ class RpcClient(): response = self.socket.recv() got_response = True else: - for i in xrange(0 ,5): + for i in xrange(0 ,10): try: response = self.socket.recv(flags = zmq.NOBLOCK) got_response = True break except zmq.error.Again: - sleep(0.1) + sleep(0.2) if not got_response: return False, "Failed To Get Server Response" @@ -88,7 +96,7 @@ class RpcClient(): # error reported by server if ("error" in response_json): - return False, response_json["error"]["message"] + return True, response_json["error"]["message"] # if no error there should be a result if ("result" not in response_json): @@ -111,23 +119,55 @@ class RpcClient(): def set_verbose (self, mode): self.verbose = mode - def connect (self): + def disconnect (self): + if self.connected: + self.socket.close(linger = 0) + self.context.destroy(linger = 0) + self.connected = False + return True, "" + else: + return False, "Not connected to server" + + def connect (self, server = None, port = None): + if self.connected: + self.disconnect() + + self.context = zmq.Context() + + self.server = (server if server else self.server) + self.port = (port if port else self.port) + + # Socket to talk to server + self.transport = "tcp://{0}:{1}".format(self.server, self.port) print "\nConnecting To RPC Server On {0}".format(self.transport) self.socket = self.context.socket(zmq.REQ) self.socket.connect(self.transport) + self.connected = True + # ping the server rc, err = self.ping_rpc_server() if not rc: - self.context.destroy(linger = 0) - return False, err + self.disconnect() + return rc, err - #print "Connection Established !\n" - print "[SUCCESS]\n" return True, "" + def reconnect (self): + # connect using current values + return self.connect() + + if not self.connected: + return False, "Not connected to server" + + # reconnect + return self.connect(self.server, self.port) + + def is_connected (self): + return self.connected + def __del__ (self): print "Shutting down RPC client\n" self.context.destroy(linger = 0) diff --git a/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp index 581f3a02..193ce8db 100644 --- a/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp @@ -33,6 +33,7 @@ TrexRpcCmdGetStatus::_run(const Json::Value ¶ms, Json::Value &result) { /* validate count */ if (params.size() != 0) { + generate_err_param_count(result, 0, params.size()); return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR); } -- cgit 1.2.3-korg From 8384612b8493a4a896e91e3bb9d5d25689a87c12 Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 20 Aug 2015 09:25:33 +0300 Subject: added args to the console --- scripts/trex-console | 2 ++ scripts/trex_console | 2 -- src/console/trex_console.py | 34 +++++++++++++++++++++++++++++++--- src/console/trex_rpc_client.py | 6 +++++- 4 files changed, 38 insertions(+), 6 deletions(-) create mode 100755 scripts/trex-console delete mode 100755 scripts/trex_console (limited to 'src/console/trex_rpc_client.py') diff --git a/scripts/trex-console b/scripts/trex-console new file mode 100755 index 00000000..50e097e7 --- /dev/null +++ b/scripts/trex-console @@ -0,0 +1,2 @@ +#!/bin/bash +../src/console/trex_console.py $@ diff --git a/scripts/trex_console b/scripts/trex_console deleted file mode 100755 index 6a79d54a..00000000 --- a/scripts/trex_console +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -/usr/bin/python ../src/console/trex_console.py diff --git a/src/console/trex_console.py b/src/console/trex_console.py index 2175fb5c..1cb8194d 100755 --- a/src/console/trex_console.py +++ b/src/console/trex_console.py @@ -1,8 +1,10 @@ -#!/usr/bin/python +#!/usr/bin/env python # -*- coding: utf-8 -*- import cmd import json import ast +import argparse +import sys from trex_rpc_client import RpcClient import trex_status @@ -78,7 +80,17 @@ class TrexConsole(cmd.Cmd): def do_connect (self, line): '''Connects to the server\n''' - rc, msg = self.rpc_client.connect() + + if line == "": + rc, msg = self.rpc_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]) + if rc: print "[SUCCESS]\n" else: @@ -207,9 +219,25 @@ class TrexConsole(cmd.Cmd): # aliasing do_exit = do_EOF = do_q = do_quit +def setParserOptions (): + parser = argparse.ArgumentParser(prog="trex_console.py") + + parser.add_argument("-s", "--server", help = "T-Rex Server [default is localhost]", + default = "localhost", + type = str) + + parser.add_argument("-p", "--port", help = "T-Rex Server Port [default is 5050]\n", + default = 5050, + type = int) + + return parser + def main (): + parser = setParserOptions() + options = parser.parse_args(sys.argv[1:]) + # RPC client - rpc_client = RpcClient("localhost", 5050) + rpc_client = RpcClient(options.server, options.port) # console try: diff --git a/src/console/trex_rpc_client.py b/src/console/trex_rpc_client.py index 2ce44afb..77d5fe1c 100644 --- a/src/console/trex_rpc_client.py +++ b/src/console/trex_rpc_client.py @@ -143,7 +143,11 @@ class RpcClient(): print "\nConnecting To RPC Server On {0}".format(self.transport) self.socket = self.context.socket(zmq.REQ) - self.socket.connect(self.transport) + try: + self.socket.connect(self.transport) + except zmq.error.ZMQError as e: + return False, "ZMQ Error: Bad server or port name: " + str(e) + self.connected = True -- cgit 1.2.3-korg