From 7ebd451ddada4d7a817f1ca2bf48e5dff96b574a Mon Sep 17 00:00:00 2001 From: grossmj Date: Thu, 24 Apr 2014 15:59:34 -0600 Subject: [PATCH] Graceful shutdown for modules and locale check for the server. --- gns3server/main.py | 43 +++++++++++++++++++++++++++- gns3server/modules/base.py | 8 ++++-- gns3server/modules/iou/iou_device.py | 4 +-- gns3server/server.py | 3 +- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/gns3server/main.py b/gns3server/main.py index 9a11139b..edd927ae 100644 --- a/gns3server/main.py +++ b/gns3server/main.py @@ -20,10 +20,14 @@ import os import datetime import sys import multiprocessing +import locale import tornado.options from gns3server.server import Server from gns3server.version import __version__ +import logging +log = logging.getLogger(__name__) + # command line options from tornado.options import define define("host", default="0.0.0.0", help="run on the given host/IP address", type=str) @@ -31,13 +35,48 @@ define("port", default=8000, help="run on the given port", type=int) define("ipc", default=False, help="use IPC for module communication", type=bool) +def locale_check(): + """ + Checks if this application runs with a correct locale (i.e. supports UTF-8 encoding) and attempt to fix + if this is not the case. + + This is to prevent UnicodeEncodeError with unicode paths when using standard library I/O operation + methods (e.g. os.stat() or os.path.*) which rely on the system or user locale. + """ + + # no need to check on Windows + if sys.platform.startswith("win"): + return + + language = encoding = None + try: + language, encoding = locale.getlocale() + except ValueError as e: + log.error("could not determine the current locale: {}".format(e)) + if not language and not encoding: + try: + log.warn("could not find a default locale, switching to C.UTF-8...") + locale.setlocale(locale.LC_ALL, ("C", "UTF-8")) + except locale.Error as e: + log.error("could not switch to the C.UTF-8 locale: {}".format(e)) + raise SystemExit + elif encoding != "UTF-8": + log.warn("your locale {}.{} encoding is not UTF-8, switching to the UTF-8 version...".format(language, encoding)) + try: + locale.setlocale(locale.LC_ALL, (language, "UTF-8")) + except locale.Error as e: + log.error("could not set an UTF-8 encoding for the {} locale: {}".format(language, e)) + else: + log.info("current locale is {}.{}".format(language, encoding)) + + def main(): """ Entry point for GNS3 server """ if sys.platform.startswith("win"): - # necessary on Windows to use freezing software + # necessary on Windows to freeze the application multiprocessing.freeze_support() current_year = datetime.date.today().year @@ -59,6 +98,8 @@ def main(): tornado.options.print_help() raise SystemExit + locale_check() + from tornado.options import options server = Server(options.host, options.port, diff --git a/gns3server/modules/base.py b/gns3server/modules/base.py index 34164f2b..5e08c053 100644 --- a/gns3server/modules/base.py +++ b/gns3server/modules/base.py @@ -54,6 +54,7 @@ class IModule(multiprocessing.Process): self._current_session = None self._current_destination = None self._current_call_id = None + self._stopping = False def _setup(self): """ @@ -128,13 +129,16 @@ class IModule(multiprocessing.Process): except KeyboardInterrupt: return + log.info("{} module has stopped".format(self.name)) + def stop(self): """ Stops the event loop. """ - if self._ioloop: - self._ioloop.stop() + if not self._stopping: + self._stopping = True + self._ioloop.add_callback_from_signal(self._ioloop.stop) def send_response(self, results): """ diff --git a/gns3server/modules/iou/iou_device.py b/gns3server/modules/iou/iou_device.py index c96953a7..f56d38b3 100644 --- a/gns3server/modules/iou/iou_device.py +++ b/gns3server/modules/iou/iou_device.py @@ -442,8 +442,8 @@ class IOUDevice(object): self._started = True except OSError as e: iou_stdout = self.read_iou_stdout() - log.error("could not start IOU: {}\n{}".format(e, iou_stdout)) - raise IOUError("could not start IOU: {}\n{}".format(e, iou_stdout)) + log.error("could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout)) + raise IOUError("could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout)) # start console support self._start_ioucon() diff --git a/gns3server/server.py b/gns3server/server.py index 0904f705..e74eb132 100644 --- a/gns3server/server.py +++ b/gns3server/server.py @@ -224,7 +224,8 @@ class Server(object): # terminate all modules for module in self._modules: - #module.join(timeout=1) +# if not sys.platform.startswith("win"): +# module.join(timeout=0.5) if module.is_alive(): log.info("terminating {}".format(module.name)) module.terminate()