Merge pull request #565 from GNS3/watch_iou

Monitor IOU NVRAM changes.
This commit is contained in:
Jeremy Grossmann 2016-06-10 22:33:56 -06:00 committed by GitHub
commit 6cd136b423
4 changed files with 28 additions and 26 deletions

View File

@ -72,23 +72,6 @@ class IOU(BaseManager):
yield from super().close_node(node_id, *args, **kwargs) yield from super().close_node(node_id, *args, **kwargs)
return node 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): def get_application_id(self, node_id):
""" """
Get an unique application identifier for IOU. Get an unique application identifier for IOU.

View File

@ -46,10 +46,10 @@ from ..base_node import BaseNode
from .utils.iou_import import nvram_import from .utils.iou_import import nvram_import
from .utils.iou_export import nvram_export from .utils.iou_export import nvram_export
from .ioucon import start_ioucon from .ioucon import start_ioucon
from gns3server.utils.file_watcher import FileWatcher
import gns3server.utils.asyncio import gns3server.utils.asyncio
import gns3server.utils.images import gns3server.utils.images
import logging import logging
import sys import sys
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -91,9 +91,17 @@ class IOUVM(BaseNode):
self._ram = 256 # Megabytes self._ram = 256 # Megabytes
self._l1_keepalives = False # used to overcome the always-up Ethernet interfaces (not supported by all IOSes). self._l1_keepalives = False # used to overcome the always-up Ethernet interfaces (not supported by all IOSes).
self._nvram_watcher = None
def _config(self): def _config(self):
return self._manager.config.get_section_config("IOU") return self._manager.config.get_section_config("IOU")
def _nvram_changed(self, path):
"""
Called when the NVRAM file has changed
"""
self.save_configs()
@asyncio.coroutine @asyncio.coroutine
def close(self): def close(self):
""" """
@ -424,6 +432,12 @@ class IOUVM(BaseNode):
self.iourc_path, self.iourc_path,
hostname)) 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): def _push_configs_to_nvram(self):
""" """
Push the startup-config and private-config content to the NVRAM. 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 startup_config_content = self.startup_config_content
if 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: try:
if not os.path.exists(nvram_file): if not os.path.exists(nvram_file):
open(nvram_file, "a").close() open(nvram_file, "a").close()
@ -489,6 +503,8 @@ class IOUVM(BaseNode):
# check if there is enough RAM to run # check if there is enough RAM to run
self.check_available_ram(self.ram) 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. # created a environment variable pointing to the iourc file.
env = os.environ.copy() 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. 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_*")): for file_path in glob.glob(os.path.join(glob.escape(self.working_dir), "nvram_*")):
shutil.move(file_path, destination) shutil.move(file_path, destination)
destination = os.path.join(self.working_dir, "vlan.dat-{:05d}".format(self.application_id)) 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. Stops the IOU process.
""" """
if self._nvram_watcher:
self._nvram_watcher.close()
self._nvram_watcher = None
if self.is_running(): if self.is_running():
# stop console support # stop console support
if self._ioucon_thread: if self._ioucon_thread:

View File

@ -23,6 +23,7 @@ class FileWatcher:
""" """
Watch for file change and call the callback when something happen Watch for file change and call the callback when something happen
""" """
def __init__(self, path, callback, delay=1): def __init__(self, path, callback, delay=1):
if not isinstance(path, str): if not isinstance(path, str):
path = str(path) path = str(path)
@ -32,7 +33,7 @@ class FileWatcher:
self._closed = False self._closed = False
try: try:
self._mtime = os.stat(path).st_mtime self._mtime = os.stat(path).st_mtime_ns
except OSError: except OSError:
self._mtime = None self._mtime = None
asyncio.get_event_loop().call_later(self._delay, self._check_config_file_change) asyncio.get_event_loop().call_later(self._delay, self._check_config_file_change)
@ -48,9 +49,10 @@ class FileWatcher:
return return
changed = False changed = False
try: try:
if os.stat(self._path).st_mtime != self._mtime: mtime = os.stat(self._path).st_mtime_ns
if mtime != self._mtime:
changed = True changed = True
self._mtime = os.stat(self._path).st_mtime self._mtime = mtime
except OSError: except OSError:
self._mtime = None self._mtime = None
if changed: if changed:
@ -64,5 +66,3 @@ class FileWatcher:
@callback.setter @callback.setter
def callback(self, val): def callback(self, val):
self._callback = val self._callback = val

View File

@ -43,4 +43,3 @@ def test_file_watcher_not_existing(async_run, tmpdir):
file.write("b") file.write("b")
async_run(asyncio.sleep(1.5)) async_run(asyncio.sleep(1.5))
callback.assert_called_with(str(file)) callback.assert_called_with(str(file))