From 6a839c4b7ba3ab10dd3ac87f7577f1c4702ae0d9 Mon Sep 17 00:00:00 2001 From: grossmj Date: Fri, 16 May 2014 12:35:48 -0600 Subject: [PATCH] Wait more time for ioucon thread to be completed. Prevent IOS to be started or stopped if the status isn't right. --- gns3server/modules/attic.py | 38 +++++++++++++++++++ .../modules/dynamips/hypervisor_manager.py | 23 ++--------- gns3server/modules/dynamips/nodes/router.py | 10 +++-- gns3server/modules/iou/iou_device.py | 30 +++++++-------- gns3server/modules/iou/ioucon.py | 5 ++- 5 files changed, 66 insertions(+), 40 deletions(-) diff --git a/gns3server/modules/attic.py b/gns3server/modules/attic.py index b928eb3d..af87e771 100644 --- a/gns3server/modules/attic.py +++ b/gns3server/modules/attic.py @@ -21,6 +21,7 @@ Useful functions... in the attic ;) import socket import errno +import time def find_unused_port(start_port, end_port, host='127.0.0.1', socket_type="TCP", ignore_ports=[]): @@ -64,3 +65,40 @@ def find_unused_port(start_port, end_port, host='127.0.0.1', socket_type="TCP", raise Exception("Could not find an unused port: {}".format(e)) raise Exception("Could not find a free port between {0} and {1}".format(start_port, end_port)) + + +def wait_socket_is_ready(host, port, wait=2.0, socket_timeout=10): + """ + Waits for a socket to be ready for wait time. + + :param host: host/address to connect to + :param port: port to connect to + :param wait: maximum wait time + :param socket_timeout: timeout for the socket + + :returns: tuple with boolean indicating if the socket is ready and the last exception + that occurred when connecting to the socket + """ + + # connect to a local address by default + # if listening to all addresses (IPv4 or IPv6) + if host == "0.0.0.0": + host = "127.0.0.1" + elif host == "::": + host = "::1" + + connection_success = False + begin = time.time() + last_exception = None + while (time.time() - begin < wait): + time.sleep(0.01) + try: + with socket.create_connection((host, port), socket_timeout): + pass + except OSError as e: + last_exception = e + continue + connection_success = True + break + + return (connection_success, last_exception) diff --git a/gns3server/modules/dynamips/hypervisor_manager.py b/gns3server/modules/dynamips/hypervisor_manager.py index 1db9f285..4a65b2f4 100644 --- a/gns3server/modules/dynamips/hypervisor_manager.py +++ b/gns3server/modules/dynamips/hypervisor_manager.py @@ -22,10 +22,10 @@ Manages Dynamips hypervisors (load-balancing etc.) from .hypervisor import Hypervisor from .dynamips_error import DynamipsError from ..attic import find_unused_port +from ..attic import wait_socket_is_ready from pkg_resources import parse_version import os -import socket import time import logging @@ -513,26 +513,9 @@ class HypervisorManager(object): :param timeout: timeout value (default is 10 seconds) """ - # connect to a local address by default - # if listening to all addresses (IPv4 or IPv6) - if host == "0.0.0.0": - host = "127.0.0.1" - elif host == "::": - host = "::1" - - connection_success = False begin = time.time() - # try to connect for 10 seconds - while(time.time() - begin < 10.0): - time.sleep(0.01) - try: - with socket.create_connection((host, port), timeout): - pass - except OSError as e: - last_exception = e - continue - connection_success = True - break + # wait for the socket for a maximum of 10 seconds. + connection_success, last_exception = wait_socket_is_ready(host, port, wait=10.0) if not connection_success: # FIXME: throw exception here diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index 0534d926..e2ce440d 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -313,9 +313,10 @@ class Router(object): At least the IOS image must be set before starting it. """ - if self.get_status() == "suspended": + status = self.get_status() + if status == "suspended": self.resume() - else: + elif status == "inactive": if not os.path.isfile(self._image): raise DynamipsError("IOS image '{}' is not accessible".format(self._image)) @@ -340,8 +341,9 @@ class Router(object): The settings are kept. """ - self._hypervisor.send("vm stop {}".format(self._name)) - log.info("router {name} [id={id}] has been stopped".format(name=self._name, id=self._id)) + if self.get_status() != "inactive": + self._hypervisor.send("vm stop {}".format(self._name)) + log.info("router {name} [id={id}] has been stopped".format(name=self._name, id=self._id)) def suspend(self): """ diff --git a/gns3server/modules/iou/iou_device.py b/gns3server/modules/iou/iou_device.py index 5f282d15..66e33f3d 100644 --- a/gns3server/modules/iou/iou_device.py +++ b/gns3server/modules/iou/iou_device.py @@ -523,25 +523,11 @@ class IOUDevice(object): Stops the IOU process. """ - # stop the IOU process - if self.is_running(): - log.info("stopping IOU instance {} PID={}".format(self._id, self._process.pid)) - try: - self._process.terminate() - self._process.wait(1) - except subprocess.TimeoutExpired: - self._process.kill() - if self._process.poll() == None: - log.warn("IOU instance {} PID={} is still running".format(self._id, - self._process.pid)) - self._process = None - self._started = False - # stop console support if self._ioucon_thead: self._ioucon_thread_stop_event.set() if self._ioucon_thead.is_alive(): - self._ioucon_thead.join(timeout=0.10) + self._ioucon_thead.join(timeout=3.0) # wait for the thread to free the console port self._ioucon_thead = None # stop iouyap @@ -557,6 +543,20 @@ class IOUDevice(object): self._id)) self._iouyap_process = None + # stop the IOU process + if self.is_running(): + log.info("stopping IOU instance {} PID={}".format(self._id, self._process.pid)) + try: + self._process.terminate() + self._process.wait(1) + except subprocess.TimeoutExpired: + self._process.kill() + if self._process.poll() == None: + log.warn("IOU instance {} PID={} is still running".format(self._id, + self._process.pid)) + self._process = None + self._started = False + def read_iou_stdout(self): """ Reads the standard output of the IOU process. diff --git a/gns3server/modules/iou/ioucon.py b/gns3server/modules/iou/ioucon.py index 77ed0fd9..a30c66e9 100644 --- a/gns3server/modules/iou/ioucon.py +++ b/gns3server/modules/iou/ioucon.py @@ -139,7 +139,10 @@ class FileLock: def unlock(self): if self.fd: # Deleting first prevents a race condition - os.unlink(self.fd.name) + try: + os.unlink(self.fd.name) + except FileNotFoundError as e: + log.debug("{}".format(e)) self.fd.close() def __enter__(self):