From bb6dec2ed238069b6a0c079d2031246704b717c4 Mon Sep 17 00:00:00 2001
From: Dan Klein <danklein10@gmail.com>
Date: Mon, 16 Nov 2015 21:59:31 +0200
Subject: created general trex console class added dynamic server async support
 fixed bugs

---
 .../trex_control_plane/client/trex_async_client.py     |  5 +++--
 .../trex_control_plane/client/trex_stateless_client.py |  2 +-
 .../trex_control_plane/console/trex_console.py         | 18 ++++++++++++++++++
 3 files changed, 22 insertions(+), 3 deletions(-)

(limited to 'scripts/automation')

diff --git a/scripts/automation/trex_control_plane/client/trex_async_client.py b/scripts/automation/trex_control_plane/client/trex_async_client.py
index d13513bf..31bec93f 100644
--- a/scripts/automation/trex_control_plane/client/trex_async_client.py
+++ b/scripts/automation/trex_control_plane/client/trex_async_client.py
@@ -151,16 +151,17 @@ class TrexAsyncStatsManager():
 
 
 class CTRexAsyncClient():
-    def __init__ (self, port):
+    def __init__ (self, server, port):
 
         self.port = port
+        self.server = server
 
         self.raw_snapshot = {}
 
         self.stats = TrexAsyncStatsManager()
 
 
-        self.tr = "tcp://localhost:{0}".format(self.port)
+        self.tr = "tcp://{0}:{1}".format(self.server, self.port)
         print "\nConnecting To ZMQ Publisher At {0}".format(self.tr)
 
         self.active = True
diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
index 4478ed3f..21f62ece 100755
--- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py
+++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
@@ -338,7 +338,7 @@ class CTRexStatelessClient(object):
         self._server_version = None
         self.__err_log = None
 
-        self._async_client = CTRexAsyncClient(async_port)
+        self._async_client = CTRexAsyncClient(server, async_port)
 
         self.streams_db = CStreamsDB()
 
diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py
index 7cb65fa6..8e8b25ec 100755
--- a/scripts/automation/trex_control_plane/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/console/trex_console.py
@@ -39,6 +39,24 @@ import parsing_opts
 __version__ = "1.0"
 
 
+class TRexGeneralCmd(cmd.Cmd):
+    def __init__(self):
+        cmd.Cmd.__init__(self)
+
+    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(cmd.Cmd):
-- 
cgit 


From 84e9d7a4a8bbb3afb4861652e2d56bc27097f794 Mon Sep 17 00:00:00 2001
From: Dan Klein <danklein10@gmail.com>
Date: Thu, 19 Nov 2015 02:30:48 +0200
Subject: History feature is DONE Fixed bugs Cleaned code, more like PEP8

---
 .../client/trex_stateless_client.py                | 55 ++++++++++------------
 .../trex_control_plane/console/trex_console.py     | 52 ++++++++++++++++----
 2 files changed, 68 insertions(+), 39 deletions(-)

(limited to 'scripts/automation')

diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
index 21f62ece..3dcfae28 100755
--- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py
+++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
@@ -139,8 +139,7 @@ class CStreamsDB(object):
 
 
 # describes a single port
-class Port:
-
+class Port(object):
     STATE_DOWN       = 0
     STATE_IDLE       = 1
     STATE_STREAMS    = 2
@@ -156,14 +155,14 @@ class Port:
 
         self.streams = {}
 
-    def err (self, msg):
+    def err(self, msg):
         return RC_ERR("port {0} : {1}".format(self.port_id, msg))
 
-    def ok (self):
+    def ok(self):
         return RC_OK()
 
     # take the port
-    def acquire (self, force = False):
+    def acquire(self, force = False):
         params = {"port_id": self.port_id,
                   "user":    self.user,
                   "force":   force}
@@ -178,7 +177,7 @@ class Port:
 
 
     # release the port
-    def release (self):
+    def release(self):
         params = {"port_id": self.port_id,
                   "handler": self.handler}
 
@@ -190,25 +189,24 @@ class Port:
         else:
             return self.err(rc.data)
 
-    def is_acquired (self):
+    def is_acquired(self):
         return (self.handler != None)
 
-    def is_active (self):
-        return (self.state == self.STATE_TX ) or (self.state == self.STATE_PAUSE)
-
-    def sync (self, sync_data):
+    def is_active(self):
+        return(self.state == self.STATE_TX ) or (self.state == self.STATE_PAUSE)
 
+    def sync(self, sync_data):
         self.handler = sync_data['handler']
-
-        if sync_data['state'] == "DOWN":
+        port_state = sync_data['state'].upper()
+        if port_state == "DOWN":
             self.state = self.STATE_DOWN
-        elif sync_data['state'] == "IDLE":
+        elif port_state == "IDLE":
             self.state = self.STATE_IDLE
-        elif sync_data['state'] == "STREAMS":
+        elif port_state == "STREAMS":
             self.state = self.STATE_STREAMS
-        elif sync_data['state'] == "TX":
+        elif port_state == "TX":
             self.state = self.STATE_TX
-        elif sync_data['state'] == "PAUSE":
+        elif port_state == "PAUSE":
             self.state = self.STATE_PAUSE
         else:
             raise Exception("port {0}: bad state received from server '{1}'".format(self.port_id, sync_data['state']))
@@ -217,14 +215,14 @@ class Port:
         
 
     # return TRUE if write commands
-    def is_port_writeable (self):
-        # operations on port can be done on state idle or state sreams
+    def is_port_writable (self):
+        # operations on port can be done on state idle or state streams
         return ((self.state == self.STATE_IDLE) or (self.state == self.STATE_STREAMS))
 
     # add stream to the port
     def add_stream (self, stream_id, stream_obj):
 
-        if not self.is_port_writeable():
+        if not self.is_port_writable():
             return self.err("Please stop port before attempting to add streams")
 
 
@@ -332,6 +330,7 @@ class CTRexStatelessClient(object):
         self.user = username
         self.comm_link = CTRexStatelessClient.CCommLink(server, sync_port, virtual)
         self.verbose = False
+        self.ports = []
         self._conn_handler = {}
         self._active_ports = set()
         self._system_info = None
@@ -378,7 +377,7 @@ class CTRexStatelessClient(object):
     ############ boot up section ################
 
     # connection sequence
-    def connect (self):
+    def connect(self):
 
         self.connected = False
 
@@ -394,7 +393,7 @@ class CTRexStatelessClient(object):
 
         self.system_info = data
 
-        # cache supported cmds
+        # cache supported commands
         rc, data = self.transmit("get_supported_cmds")
         if not rc:
             return RC_ERR(data)
@@ -402,8 +401,7 @@ class CTRexStatelessClient(object):
         self.supported_cmds = data
 
         # create ports
-        self.ports = []
-        for port_id in xrange(0, self.get_port_count()):
+        for port_id in xrange(self.get_port_count()):
             self.ports.append(Port(port_id, self.user, self.transmit))
 
         # acquire all ports
@@ -485,7 +483,6 @@ class CTRexStatelessClient(object):
             return RC_ERR(data)
 
         for port_info in data:
-
             rc = self.ports[port_info['port_id']].sync(port_info)
             if rc.bad():
                 return rc
@@ -619,23 +616,23 @@ class CTRexStatelessClient(object):
 
     ######################### Console (high level) API #########################
 
-    def cmd_ping (self):
+    def cmd_ping(self):
         rc = self.ping()
         rc.annotate("Pinging the server on '{0}' port '{1}': ".format(self.get_connection_ip(), self.get_connection_port()))
         return rc
 
-    def cmd_connect (self):
+    def cmd_connect(self):
         rc = self.connect()
         rc.annotate()
         return rc
 
-    def cmd_disconnect (self):
+    def cmd_disconnect(self):
         rc = self.disconnect()
         rc.annotate()
         return rc
 
     # reset
-    def cmd_reset (self):
+    def cmd_reset(self):
 
 
         # sync with the server
diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py
index 8e8b25ec..ea2f5f12 100755
--- a/scripts/automation/trex_control_plane/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/console/trex_console.py
@@ -23,6 +23,7 @@ import json
 import ast
 import argparse
 import random
+import readline
 import string
 import os
 import sys
@@ -36,12 +37,38 @@ import trex_status
 import parsing_opts
 
 
-__version__ = "1.0"
+__version__ = "1.1"
 
 
 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):
+            os.makedirs(self._history_file_dir)
+        # os.mknod(self._history_file)
+        readline.write_history_file(self._history_file)
+        return
 
     def emptyline(self):
         """Called when an empty line is entered in response to the prompt.
@@ -57,15 +84,22 @@ class TRexGeneralCmd(cmd.Cmd):
         dotext = 'do_'+text
         return [a[3:]+' ' for a in self.get_names() if a.startswith(dotext)]
 
+    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()
+        return line
+
+
 #
 # main console object
-class TRexConsole(cmd.Cmd):
+class TRexConsole(TRexGeneralCmd):
     """Trex Console"""
 
-    def __init__(self, stateless_client, acquire_all_ports = True, verbose = False):
-        cmd.Cmd.__init__(self)
-
+    def __init__(self, stateless_client, acquire_all_ports=True, verbose=False):
         self.stateless_client = stateless_client
+        TRexGeneralCmd.__init__(self)
+
 
         self.verbose = verbose
         self.acquire_all_ports = acquire_all_ports
@@ -78,11 +112,9 @@ class TRexConsole(cmd.Cmd):
 
     ################### internal section ########################
 
-    # a cool hack - i stole this function and added space
-    def completenames(self, text, *ignored):
-        dotext = 'do_'+text
-        return [a[3:]+' ' for a in self.get_names() if a.startswith(dotext)]
-
+    def get_console_identifier(self):
+        return "{context}_{server}".format(context=self.__class__.__name__,
+                                           server=self.stateless_client.get_system_info()['hostname'])
     
     def register_main_console_methods(self):
         main_names = set(self.trex_console.get_names()).difference(set(dir(self.__class__)))
-- 
cgit