Support active connect, overwrite log

Added options:
  --switch-ip   If set, actively connect to this switch on controller-port
  --log-append  Append to existing log

The default log file generation behavior has changed.  By default, now
over-write the existing log.  To have the old append behavior, use the
--log-append option.

Active switch connections have been tested, but not exhaustively.  It
shold still be considered experimental.  The old behavior (listen for
switch connections) should be unchanged.
diff --git a/oft b/oft
index 9e92a99..562a670 100755
--- a/oft
+++ b/oft
@@ -153,11 +153,13 @@
     "param"              : None,
     "platform"           : "local",
     "platform_args"      : None,
-    "controller_host"    : "0.0.0.0",
+    "switch_ip"          : None,  # If not none, actively connect to switch
+    "controller_host"    : "0.0.0.0",  # For passive bind
     "controller_port"    : 6633,
     "relax"              : False,
     "test_spec"          : "all",
     "log_file"           : "oft.log",
+    "log_append"         : False,
     "list"               : False,
     "list_test_names"    : False, 
     "debug"              : _debug_default,
@@ -225,6 +227,8 @@
     parser.add_option("-P", "--platform", help=plat_help)
     parser.add_option("-H", "--host", dest="controller_host",
                       help="The IP/name of the test controller host")
+    parser.add_option("-S", "--switch-ip", dest="switch_ip",
+                      help="If set, actively connect to this switch by IP")
     parser.add_option("-p", "--port", dest="controller_port",
                       type="int", help="Port number of the test controller")
     test_list_help = """Indicate tests to run.  Valid entries are "all" (the
@@ -236,6 +240,8 @@
     parser.add_option("-T", "--test-spec", "--test-list", help=test_list_help)
     parser.add_option("--log-file", 
                       help="Name of log file, empty string to log to console")
+    parser.add_option("--log-append", action="store_true",
+                      help="Do not delete log file if specified")
     parser.add_option("--debug",
                       help="Debug lvl: debug, info, warning, error, critical")
     parser.add_option("--port-count", type="int",
@@ -312,7 +318,9 @@
     """
     _format = "%(asctime)s  %(name)-10s: %(levelname)-8s: %(message)s"
     _datefmt = "%H:%M:%S"
+    _mode = config["log_append"] and "a" or "w"
     logging.basicConfig(filename=config["log_file"],
+                        filemode=_mode,
                         level=config["dbg_level"],
                         format=_format, datefmt=_datefmt)
 
diff --git a/src/python/oftest/base_tests.py b/src/python/oftest/base_tests.py
index 3664d9f..734e213 100644
--- a/src/python/oftest/base_tests.py
+++ b/src/python/oftest/base_tests.py
@@ -25,6 +25,7 @@
     def setUp(self):
         logging.info("** START TEST CASE " + str(self))
         self.controller = controller.Controller(
+            switch=config["switch_ip"],
             host=config["controller_host"],
             port=config["controller_port"])
         # clean_shutdown should be set to False to force quit app
diff --git a/src/python/oftest/controller.py b/src/python/oftest/controller.py
index fff8534..b4c3ac5 100644
--- a/src/python/oftest/controller.py
+++ b/src/python/oftest/controller.py
@@ -86,6 +86,7 @@
     echo replies
     @var initial_hello If true, will send a hello message immediately
     upon connecting to the switch
+    @var switch If not None, do an active connection to the switch
     @var host The host to use for connect
     @var port The port to connect on 
     @var packets_total Total number of packets received
@@ -94,7 +95,7 @@
     @var dbg_state Debug indication of state
     """
 
-    def __init__(self, host='127.0.0.1', port=6633, max_pkts=1024):
+    def __init__(self, switch=None, host='127.0.0.1', port=6633, max_pkts=1024):
         Thread.__init__(self)
         # Socket related
         self.rcv_size = RCV_SIZE_DEFAULT
@@ -127,7 +128,8 @@
 
         # Settings
         self.max_pkts = max_pkts
-        self.passive = True
+        self.switch = switch
+        self.passive = not self.switch
         self.host = host
         self.port = port
         self.dbg_state = "init"
@@ -282,7 +284,7 @@
         @returns 0 on success, -1 on error
         """
 
-        if s and s == self.listen_socket:
+        if self.passive and s and s == self.listen_socket:
             if self.switch_socket:
                 self.logger.warning("Ignoring incoming connection; already connected to switch")
                 (sock, addr) = self.listen_socket.accept()
@@ -330,6 +332,23 @@
 
         return 0
 
+    def active_connect(self):
+        """
+        Actively connect to a switch IP addr
+        """
+        try:
+            self.logger.info("Trying active connection to %s" % self.switch)
+            soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            soc.connect((self.switch, self.port))
+            self.logger.info("Connected to " + self.switch + " on " +
+                         str(self.port))
+            self.switch_addr = (self.switch, self.port)
+            return soc
+        except (StandardError, socket.error), e:
+            self.logger.error("Could not connect to %s at %d:: %s" % 
+                              (self.switch, self.port, str(e)))
+        return None
+
     def run(self):
         """
         Activity function for class
@@ -348,18 +367,19 @@
         self.dbg_state = "starting"
 
         # Create listen socket
-        self.logger.info("Create/listen at " + self.host + ":" + 
-                 str(self.port))
-        self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.listen_socket.setsockopt(socket.SOL_SOCKET, 
-                                      socket.SO_REUSEADDR, 1)
-        self.listen_socket.bind((self.host, self.port))
-        self.dbg_state = "listening"
-        self.listen_socket.listen(LISTEN_QUEUE_SIZE)
+        if self.passive:
+            self.logger.info("Create/listen at " + self.host + ":" + 
+                             str(self.port))
+            self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            self.listen_socket.setsockopt(socket.SOL_SOCKET, 
+                                          socket.SO_REUSEADDR, 1)
+            self.listen_socket.bind((self.host, self.port))
+            self.dbg_state = "listening"
+            self.listen_socket.listen(LISTEN_QUEUE_SIZE)
 
-        self.logger.info("Waiting for switch connection")
-        self.socs = [self.listen_socket]
-        self.dbg_state = "running"
+            self.logger.info("Listening for switch connection")
+            self.socs = [self.listen_socket]
+            self.dbg_state = "running"
 
         while self.active:
             try:
@@ -391,8 +411,28 @@
         @return Boolean, True if connected
         """
 
-        with self.connect_cv:
-            timed_wait(self.connect_cv, lambda: self.switch_socket, timeout=timeout)
+        if not self.passive:  # Do active connection now
+            self.logger.info("Attempting to connect to %s on port %s" %
+                             (self.switch, str(self.port)))
+            soc = self.active_connect()
+            if soc:
+                self.logger.info("Connected to %s", self.switch)
+                self.socs = [soc]
+                self.dbg_state = "running"
+                self.switch_socket = soc
+                with self.connect_cv:
+                    if self.initial_hello:
+                        self.message_send(hello())
+                    self.connect_cv.notify() # Notify anyone waiting
+            else:
+                self.logger.error("Could not actively connect to switch %s",
+                                  self.switch)
+                self.active = False
+        else:
+            with self.connect_cv:
+                timed_wait(self.connect_cv, lambda: self.switch_socket,
+                           timeout=timeout)
+
         return self.switch_socket is not None
         
     def disconnect(self, timeout=-1):
@@ -620,6 +660,7 @@
         string += "  parse errors    " + str(self.parse_errors) + "\n"
         string += "  sock errrors    " + str(self.socket_errors) + "\n"
         string += "  max pkts        " + str(self.max_pkts) + "\n"
+        string += "  target switch   " + str(self.switch) + "\n"
         string += "  host            " + str(self.host) + "\n"
         string += "  port            " + str(self.port) + "\n"
         string += "  keep_alive      " + str(self.keep_alive) + "\n"