From 69334665d2b8292db0d75544c7f8a05609de6fdb Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Fri, 10 Jun 2016 18:26:01 +0200 Subject: [PATCH] Monitor IOU nvram for change With the save as you go we need to save the startup config when a change appear instead of the old commit system. --- gns3server/compute/iou/__init__.py | 17 ----------------- gns3server/compute/iou/iou_vm.py | 26 +++++++++++++++++++++++--- gns3server/utils/file_watcher.py | 10 +++++----- tests/utils/test_file_watcher.py | 1 - 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/gns3server/compute/iou/__init__.py b/gns3server/compute/iou/__init__.py index 7d7ff0f9..d101e0d1 100644 --- a/gns3server/compute/iou/__init__.py +++ b/gns3server/compute/iou/__init__.py @@ -72,23 +72,6 @@ class IOU(BaseManager): yield from super().close_node(node_id, *args, **kwargs) return node - @asyncio.coroutine - def project_committed(self, project): - """ - Called when a project has been committed. - - :param project: Project instance - """ - - # save the configs when the project is committed - for node in self._nodes.copy().values(): - if node.project.id == project.id: - try: - node.save_configs() - except IOUError as e: - log.warning(e) - continue - def get_application_id(self, node_id): """ Get an unique application identifier for IOU. diff --git a/gns3server/compute/iou/iou_vm.py b/gns3server/compute/iou/iou_vm.py index 2c7e3aee..50ab00c2 100644 --- a/gns3server/compute/iou/iou_vm.py +++ b/gns3server/compute/iou/iou_vm.py @@ -46,10 +46,10 @@ from ..base_node import BaseNode from .utils.iou_import import nvram_import from .utils.iou_export import nvram_export from .ioucon import start_ioucon +from gns3server.utils.file_watcher import FileWatcher import gns3server.utils.asyncio import gns3server.utils.images - import logging import sys log = logging.getLogger(__name__) @@ -91,9 +91,17 @@ class IOUVM(BaseNode): self._ram = 256 # Megabytes self._l1_keepalives = False # used to overcome the always-up Ethernet interfaces (not supported by all IOSes). + self._nvram_watcher = None + def _config(self): return self._manager.config.get_section_config("IOU") + def _nvram_changed(self, path): + """ + Called when the NVRAM file as changed + """ + self.save_configs() + @asyncio.coroutine def close(self): """ @@ -424,6 +432,12 @@ class IOUVM(BaseNode): self.iourc_path, hostname)) + def _nvram_file(self): + """ + Path to the nvram file + """ + return os.path.join(self.working_dir, "nvram_{:05d}".format(self.application_id)) + def _push_configs_to_nvram(self): """ Push the startup-config and private-config content to the NVRAM. @@ -431,7 +445,7 @@ class IOUVM(BaseNode): startup_config_content = self.startup_config_content if startup_config_content: - nvram_file = os.path.join(self.working_dir, "nvram_{:05d}".format(self.application_id)) + nvram_file = self._nvram_file() try: if not os.path.exists(nvram_file): open(nvram_file, "a").close() @@ -489,6 +503,8 @@ class IOUVM(BaseNode): # check if there is enough RAM to run self.check_available_ram(self.ram) + self._nvram_watcher = FileWatcher(self._nvram_file(), self._nvram_changed) + # created a environment variable pointing to the iourc file. env = os.environ.copy() @@ -544,7 +560,7 @@ class IOUVM(BaseNode): Before starting the VM, rename the nvram and vlan.dat files with the correct IOU application identifier. """ - destination = os.path.join(self.working_dir, "nvram_{:05d}".format(self.application_id)) + destination = self._nvram_file() for file_path in glob.glob(os.path.join(glob.escape(self.working_dir), "nvram_*")): shutil.move(file_path, destination) destination = os.path.join(self.working_dir, "vlan.dat-{:05d}".format(self.application_id)) @@ -644,6 +660,10 @@ class IOUVM(BaseNode): Stops the IOU process. """ + if self._nvram_watcher: + self._nvram_watcher.close() + self._nvram_watcher = None + if self.is_running(): # stop console support if self._ioucon_thread: diff --git a/gns3server/utils/file_watcher.py b/gns3server/utils/file_watcher.py index 0ca7c101..2de0f7c1 100644 --- a/gns3server/utils/file_watcher.py +++ b/gns3server/utils/file_watcher.py @@ -23,6 +23,7 @@ class FileWatcher: """ Watch for file change and call the callback when something happen """ + def __init__(self, path, callback, delay=1): if not isinstance(path, str): path = str(path) @@ -32,7 +33,7 @@ class FileWatcher: self._closed = False try: - self._mtime = os.stat(path).st_mtime + self._mtime = os.stat(path).st_mtime_ns except OSError: self._mtime = None asyncio.get_event_loop().call_later(self._delay, self._check_config_file_change) @@ -48,9 +49,10 @@ class FileWatcher: return changed = False try: - if os.stat(self._path).st_mtime != self._mtime: + mtime = os.stat(self._path).st_mtime_ns + if mtime != self._mtime: changed = True - self._mtime = os.stat(self._path).st_mtime + self._mtime = mtime except OSError: self._mtime = None if changed: @@ -64,5 +66,3 @@ class FileWatcher: @callback.setter def callback(self, val): self._callback = val - - diff --git a/tests/utils/test_file_watcher.py b/tests/utils/test_file_watcher.py index 84e86bc6..11939d5f 100644 --- a/tests/utils/test_file_watcher.py +++ b/tests/utils/test_file_watcher.py @@ -43,4 +43,3 @@ def test_file_watcher_not_existing(async_run, tmpdir): file.write("b") async_run(asyncio.sleep(1.5)) callback.assert_called_with(str(file)) -