diff options
author | 2016-02-08 10:55:20 -0500 | |
---|---|---|
committer | 2016-02-08 10:55:20 -0500 | |
commit | 6107c1ca4aa485c5971ff3326513b8f4934f7ac1 (patch) | |
tree | a109d80501bd087e3219f68c186fb55bc17e090a /scripts/automation/trex_control_plane/console/trex_console.py | |
parent | f5a5e50bfe046148a20f6ce578d6082119dec2c0 (diff) |
huge refactor - again
Diffstat (limited to 'scripts/automation/trex_control_plane/console/trex_console.py')
-rwxr-xr-x | scripts/automation/trex_control_plane/console/trex_console.py | 784 |
1 files changed, 0 insertions, 784 deletions
diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py deleted file mode 100755 index 45428b89..00000000 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ /dev/null @@ -1,784 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Dan Klein, 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. -""" -import subprocess -import cmd -import json -import ast -import argparse -import random -import readline -import string -import os -import sys -import tty, termios - -from trex_control_plane.stl.api import * - -from trex_control_plane.common.text_opts import * -from trex_control_plane.client_utils.general_utils import user_input, get_current_user -from trex_control_plane.client_utils import parsing_opts - - -import trex_tui - -from functools import wraps - -__version__ = "1.1" - -# console custom logger -class ConsoleLogger(LoggerApi): - def __init__ (self): - self.prompt_redraw = None - - def write (self, msg, newline = True): - if newline: - print msg - else: - print msg, - - def flush (self): - sys.stdout.flush() - - # override this for the prompt fix - def async_log (self, msg, level = LoggerApi.VERBOSE_REGULAR, newline = True): - self.log(msg, level, newline) - if ( (self.level >= LoggerApi.VERBOSE_REGULAR) and self.prompt_redraw ): - self.prompt_redraw() - self.flush() - - -def set_window_always_on_top (title): - # we need the GDK module, if not available - ignroe this command - try: - import gtk.gdk - except ImportError: - return - - # search the window and set it as above - root = gtk.gdk.get_default_root_window() - - for id in root.property_get('_NET_CLIENT_LIST')[2]: - w = gtk.gdk.window_foreign_new(id) - if w: - name = w.property_get('WM_NAME')[2] - if name == title: - w.set_keep_above(True) - gtk.gdk.window_process_all_updates() - break - - -class TRexGeneralCmd(cmd.Cmd): - def __init__(self): - cmd.Cmd.__init__(self) - # configure history behaviour - self._history_file_dir = "/tmp/trex/console/" - self._history_file = self.get_history_file_full_path() - readline.set_history_length(100) - # load history, if any - self.load_console_history() - - - def get_console_identifier(self): - return self.__class__.__name__ - - def get_history_file_full_path(self): - return "{dir}{filename}.hist".format(dir=self._history_file_dir, - filename=self.get_console_identifier()) - - def load_console_history(self): - if os.path.exists(self._history_file): - readline.read_history_file(self._history_file) - return - - def save_console_history(self): - if not os.path.exists(self._history_file_dir): - # make the directory available for every user - try: - original_umask = os.umask(0) - os.makedirs(self._history_file_dir, mode = 0777) - finally: - os.umask(original_umask) - - - # os.mknod(self._history_file) - readline.write_history_file(self._history_file) - return - - def print_history (self): - - length = readline.get_current_history_length() - - for i in xrange(1, length + 1): - cmd = readline.get_history_item(i) - print "{:<5} {:}".format(i, cmd) - - def get_history_item (self, index): - length = readline.get_current_history_length() - if index > length: - print format_text("please select an index between {0} and {1}".format(0, length)) - return None - - return readline.get_history_item(index) - - - def emptyline(self): - """Called when an empty line is entered in response to the prompt. - - This overriding is such that when empty line is passed, **nothing happens**. - """ - return - - def completenames(self, text, *ignored): - """ - This overriding is such that a space is added to name completion. - """ - dotext = 'do_'+text - return [a[3:]+' ' for a in self.get_names() if a.startswith(dotext)] - - -# -# main console object -class TRexConsole(TRexGeneralCmd): - """Trex Console""" - - def __init__(self, stateless_client, verbose = False): - - self.stateless_client = stateless_client - - TRexGeneralCmd.__init__(self) - - self.tui = trex_tui.TrexTUI(stateless_client) - self.terminal = None - - self.verbose = verbose - - self.intro = "\n-=TRex Console v{ver}=-\n".format(ver=__version__) - self.intro += "\nType 'help' or '?' for supported actions\n" - - self.postcmd(False, "") - - - ################### internal section ######################## - - def prompt_redraw (self): - self.postcmd(False, "") - sys.stdout.write("\n" + self.prompt + readline.get_line_buffer()) - sys.stdout.flush() - - - def verify_connected(f): - @wraps(f) - def wrap(*args): - inst = args[0] - func_name = f.__name__ - if func_name.startswith("do_"): - func_name = func_name[3:] - - if not inst.stateless_client.is_connected(): - print format_text("\n'{0}' cannot be executed on offline mode\n".format(func_name), 'bold') - return - - ret = f(*args) - return ret - - return wrap - - # TODO: remove this ugly duplication - def verify_connected_and_rw (f): - @wraps(f) - def wrap(*args): - inst = args[0] - func_name = f.__name__ - if func_name.startswith("do_"): - func_name = func_name[3:] - - if not inst.stateless_client.is_connected(): - print format_text("\n'{0}' cannot be executed on offline mode\n".format(func_name), 'bold') - return - - if inst.stateless_client.is_all_ports_acquired(): - print format_text("\n'{0}' cannot be executed on read only mode\n".format(func_name), 'bold') - return - - rc = f(*args) - return rc - - return wrap - - - def get_console_identifier(self): - return "{context}_{server}".format(context=get_current_user(), - server=self.stateless_client.get_connection_info()['server']) - - def register_main_console_methods(self): - main_names = set(self.trex_console.get_names()).difference(set(dir(self.__class__))) - for name in main_names: - for prefix in 'do_', 'help_', 'complete_': - if name.startswith(prefix): - self.__dict__[name] = getattr(self.trex_console, name) - - def precmd(self, line): - # before doing anything, save history snapshot of the console - # this is done before executing the command in case of ungraceful application exit - self.save_console_history() - - lines = line.split(';') - - for line in lines: - stop = self.onecmd(line) - stop = self.postcmd(stop, line) - if stop: - return "quit" - - return "" - - - def postcmd(self, stop, line): - - if not self.stateless_client.is_connected(): - self.prompt = "TRex (offline) > " - self.supported_rpc = None - return stop - - if self.stateless_client.is_all_ports_acquired(): - self.prompt = "TRex (read only) > " - return stop - - - self.prompt = "TRex > " - - return stop - - def default(self, line): - print "'{0}' is an unrecognized command. type 'help' or '?' for a list\n".format(line) - - @staticmethod - def tree_autocomplete(text): - dir = os.path.dirname(text) - if dir: - path = dir - else: - path = "." - - - start_string = os.path.basename(text) - - targets = [] - - for x in os.listdir(path): - if x.startswith(start_string): - y = os.path.join(path, x) - if os.path.isfile(y): - targets.append(x + ' ') - elif os.path.isdir(y): - targets.append(x + '/') - - return targets - - - ####################### shell commands ####################### - @verify_connected - def do_ping (self, line): - '''Ping the server\n''' - self.stateless_client.ping() - - - # set verbose on / off - def do_verbose(self, line): - '''Shows or set verbose mode\n''' - if line == "": - print "\nverbose is " + ("on\n" if self.verbose else "off\n") - - elif line == "on": - self.verbose = True - self.stateless_client.set_verbose("high") - print format_text("\nverbose set to on\n", 'green', 'bold') - - elif line == "off": - self.verbose = False - self.stateless_client.set_verbose("normal") - print format_text("\nverbose set to off\n", 'green', 'bold') - - else: - print format_text("\nplease specify 'on' or 'off'\n", 'bold') - - # show history - def help_history (self): - self.do_history("-h") - - def do_shell (self, line): - return self.do_history(line) - - - def do_history (self, line): - '''Manage the command history\n''' - - item = parsing_opts.ArgumentPack(['item'], - {"nargs": '?', - 'metavar': 'item', - 'type': parsing_opts.check_negative, - 'help': "an history item index", - 'default': 0}) - - parser = parsing_opts.gen_parser(self, - "history", - self.do_history.__doc__, - item) - - opts = parser.parse_args(line.split()) - if opts is None: - return - - if opts.item == 0: - self.print_history() - else: - cmd = self.get_history_item(opts.item) - if cmd == None: - return - - print "Executing '{0}'".format(cmd) - - return self.onecmd(cmd) - - - - ############### connect - def do_connect (self, line): - '''Connects to the server\n''' - - self.stateless_client.connect_line(line) - - - def do_disconnect (self, line): - '''Disconnect from the server\n''' - - self.stateless_client.disconnect_line(line) - - - ############### start - - def complete_start(self, text, line, begidx, endidx): - s = line.split() - l = len(s) - - file_flags = parsing_opts.get_flags(parsing_opts.FILE_PATH) - - if (l > 1) and (s[l - 1] in file_flags): - return TRexConsole.tree_autocomplete("") - - if (l > 2) and (s[l - 2] in file_flags): - return TRexConsole.tree_autocomplete(s[l - 1]) - - @verify_connected_and_rw - def do_start(self, line): - '''Start selected traffic in specified port(s) on TRex\n''' - - self.stateless_client.start_line(line) - - - - - def help_start(self): - self.do_start("-h") - - ############# stop - @verify_connected_and_rw - def do_stop(self, line): - '''stops port(s) transmitting traffic\n''' - - self.stateless_client.stop_line(line) - - def help_stop(self): - self.do_stop("-h") - - ############# update - @verify_connected_and_rw - def do_update(self, line): - '''update speed of port(s)currently transmitting traffic\n''' - - self.stateless_client.update_line(line) - - def help_update (self): - self.do_update("-h") - - ############# pause - @verify_connected_and_rw - def do_pause(self, line): - '''pause port(s) transmitting traffic\n''' - - self.stateless_client.pause_line(line) - - ############# resume - @verify_connected_and_rw - def do_resume(self, line): - '''resume port(s) transmitting traffic\n''' - - self.stateless_client.resume_line(line) - - - - ########## reset - @verify_connected_and_rw - def do_reset (self, line): - '''force stop all ports\n''' - self.stateless_client.reset_line(line) - - - ######### validate - @verify_connected - def do_validate (self, line): - '''validates port(s) stream configuration\n''' - - self.stateless_client.validate_line(line) - - - @verify_connected - def do_stats(self, line): - '''Fetch statistics from TRex server by port\n''' - self.stateless_client.show_stats_line(line) - - - def help_stats(self): - self.do_stats("-h") - - @verify_connected - def do_streams(self, line): - '''Fetch statistics from TRex server by port\n''' - self.stateless_client.show_streams_line(line) - - - def help_streams(self): - self.do_streams("-h") - - @verify_connected - def do_clear(self, line): - '''Clear cached local statistics\n''' - self.stateless_client.clear_stats_line(line) - - - def help_clear(self): - self.do_clear("-h") - - - def help_events (self): - self.do_events("-h") - - def do_events (self, line): - '''shows events recieved from server\n''' - - x = parsing_opts.ArgumentPack(['-c','--clear'], - {'action' : "store_true", - 'default': False, - 'help': "clear the events log"}) - - parser = parsing_opts.gen_parser(self, - "events", - self.do_events.__doc__, - x) - - opts = parser.parse_args(line.split()) - if opts is None: - return - - events = self.stateless_client.get_events() - for ev in events: - print ev - - if opts.clear: - self.stateless_client.clear_events() - print format_text("\n\nEvent log was cleared\n\n") - - - # tui - @verify_connected - def do_tui (self, line): - '''Shows a graphical console\n''' - - parser = parsing_opts.gen_parser(self, - "tui", - self.do_tui.__doc__, - parsing_opts.XTERM) - - opts = parser.parse_args(line.split()) - if opts is None: - return - - if opts.xterm: - - info = self.stateless_client.get_connection_info() - - exe = './trex-console --top -t -q -s {0} -p {1} --async_port {2}'.format(info['server'], info['sync_port'], info['async_port']) - cmd = ['xterm', '-geometry', '111x42', '-sl', '0', '-title', 'trex_tui', '-e', exe] - self.terminal = subprocess.Popen(cmd) - - return - - - with self.stateless_client.logger.supress(): - self.tui.show() - - - def help_tui (self): - do_tui("-h") - - - # quit function - def do_quit(self, line): - '''Exit the client\n''' - return True - - - def do_help (self, line): - '''Shows This Help Screen\n''' - if line: - try: - func = getattr(self, 'help_' + line) - except AttributeError: - try: - doc = getattr(self, 'do_' + line).__doc__ - if doc: - self.stdout.write("%s\n"%str(doc)) - return - except AttributeError: - pass - self.stdout.write("%s\n"%str(self.nohelp % (line,))) - return - func() - return - - print "\nSupported Console Commands:" - print "----------------------------\n" - - cmds = [x[3:] for x in self.get_names() if x.startswith("do_")] - for cmd in cmds: - if ( (cmd == "EOF") or (cmd == "q") or (cmd == "exit") or (cmd == "h")): - 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) - - # a custorm cmdloop wrapper - def start(self): - while True: - try: - self.cmdloop() - break - except KeyboardInterrupt as e: - if not readline.get_line_buffer(): - raise KeyboardInterrupt - else: - print "" - self.intro = None - continue - - if self.terminal: - self.terminal.kill() - - # aliases - do_exit = do_EOF = do_q = do_quit - do_h = do_history - - -# run a script of commands -def run_script_file (self, filename, stateless_client): - - self.logger.log(format_text("\nRunning script file '{0}'...".format(filename), 'bold')) - - with open(filename) as f: - script_lines = f.readlines() - - cmd_table = {} - - # register all the commands - cmd_table['start'] = stateless_client.start_line - cmd_table['stop'] = stateless_client.stop_line - cmd_table['reset'] = stateless_client.reset_line - - for index, line in enumerate(script_lines, start = 1): - line = line.strip() - if line == "": - continue - if line.startswith("#"): - continue - - sp = line.split(' ', 1) - cmd = sp[0] - if len(sp) == 2: - args = sp[1] - else: - args = "" - - stateless_client.logger.log(format_text("Executing line {0} : '{1}'\n".format(index, line))) - - if not cmd in cmd_table: - print "\n*** Error at line {0} : '{1}'\n".format(index, line) - stateless_client.logger.log(format_text("unknown command '{0}'\n".format(cmd), 'bold')) - return False - - cmd_table[cmd](args) - - stateless_client.logger.log(format_text("\n[Done]", 'bold')) - - return True - - -# -def is_valid_file(filename): - if not os.path.isfile(filename): - raise argparse.ArgumentTypeError("The file '%s' does not exist" % filename) - - return filename - - - -def setParserOptions(): - parser = argparse.ArgumentParser(prog="trex_console.py") - - parser.add_argument("-s", "--server", help = "TRex Server [default is localhost]", - default = "localhost", - type = str) - - parser.add_argument("-p", "--port", help = "TRex Server Port [default is 4501]\n", - default = 4501, - type = int) - - parser.add_argument("--async_port", help = "TRex ASync Publisher Port [default is 4500]\n", - default = 4500, - dest='pub', - type = int) - - parser.add_argument("-u", "--user", help = "User Name [default is currently logged in user]\n", - default = get_current_user(), - type = str) - - parser.add_argument("-v", "--verbose", dest="verbose", - action="store_true", help="Switch ON verbose option. Default is: OFF.", - default = False) - - - parser.add_argument("--no_acquire", dest="acquire", - action="store_false", help="Acquire all ports on connect. Default is: ON.", - default = True) - - parser.add_argument("--batch", dest="batch", - nargs = 1, - type = is_valid_file, - help = "Run the console in a batch mode with file", - default = None) - - parser.add_argument("-t", "--tui", dest="tui", - action="store_true", help="Starts with TUI mode", - default = False) - - parser.add_argument("-x", "--xtui", dest="xtui", - action="store_true", help="Starts with XTERM TUI mode", - default = False) - - parser.add_argument("--top", dest="top", - action="store_true", help="Set the window as always on top", - default = False) - - parser.add_argument("-q", "--quiet", dest="quiet", - action="store_true", help="Starts with all outputs suppressed", - default = False) - - return parser - - -def main(): - parser = setParserOptions() - options = parser.parse_args() - - if options.xtui: - options.tui = True - - # always on top - if options.top: - set_window_always_on_top('trex_tui') - - - # Stateless client connection - if options.quiet: - verbose_level = LoggerApi.VERBOSE_QUIET - elif options.verbose: - verbose_level = LoggerApi.VERBOSE_HIGH - else: - verbose_level = LoggerApi.VERBOSE_REGULAR - - # Stateless client connection - logger = ConsoleLogger() - stateless_client = STLClient(username = options.user, - server = options.server, - sync_port = options.port, - async_port = options.pub, - verbose_level = verbose_level, - logger = logger) - - # TUI or no acquire will give us READ ONLY mode - try: - stateless_client.connect() - except STLError as e: - logger.log("Log:\n" + format_text(e.brief() + "\n", 'bold')) - return - - if not options.tui and options.acquire: - try: - # acquire all ports - stateless_client.acquire() - except STLError as e: - logger.log("Log:\n" + format_text(e.brief() + "\n", 'bold')) - logger.log(format_text("\nSwitching to read only mode - only few commands will be available", 'bold')) - - - # a script mode - if options.batch: - cont = run_script_file(options.batch[0], stateless_client) - if not cont: - return - - # console - try: - console = TRexConsole(stateless_client, options.verbose) - logger.prompt_redraw = console.prompt_redraw - - # TUI - if options.tui: - console.do_tui("-x" if options.xtui else "") - else: - console.start() - - except KeyboardInterrupt as e: - print "\n\n*** Caught Ctrl + C... Exiting...\n\n" - - finally: - with stateless_client.logger.supress(): - stateless_client.disconnect(stop_traffic = False) - -if __name__ == '__main__': - - main() - |