From 71e2586e176232f574b14be8d03c0d9ccd32daa6 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Mon, 4 May 2015 18:42:32 -0600 Subject: [PATCH] Refactors how startup-config and private-config are handled for IOS routers. --- .../handlers/api/dynamips_vm_handler.py | 31 +++++++++++++++++-- gns3server/modules/dynamips/__init__.py | 31 +++++++++---------- gns3server/modules/dynamips/nodes/router.py | 15 ++++++--- gns3server/schemas/dynamips_vm.py | 1 - 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/gns3server/handlers/api/dynamips_vm_handler.py b/gns3server/handlers/api/dynamips_vm_handler.py index ff3c3707..5b501815 100644 --- a/gns3server/handlers/api/dynamips_vm_handler.py +++ b/gns3server/handlers/api/dynamips_vm_handler.py @@ -26,6 +26,7 @@ from ...schemas.dynamips_vm import VM_CAPTURE_SCHEMA from ...schemas.dynamips_vm import VM_OBJECT_SCHEMA from ...schemas.dynamips_vm import VM_CONFIGS_SCHEMA from ...modules.dynamips import Dynamips +from ...modules.dynamips.dynamips_error import DynamipsError from ...modules.project_manager import ProjectManager DEFAULT_CHASSIS = { @@ -358,13 +359,39 @@ class DynamipsVMHandler: project_id=request.match_info["project_id"]) startup_config_base64, private_config_base64 = yield from vm.extract_config() + module_workdir = vm.project.module_working_directory(dynamips_manager.module_name.lower()) result = {} if startup_config_base64: - startup_config_content = base64.b64decode(startup_config_base64).decode(errors='replace') + startup_config_content = base64.b64decode(startup_config_base64).decode("utf-8", errors='replace') result["startup_config_content"] = startup_config_content + else: + # nvram doesn't contain anything if the router has not been started at least once + # in this case just use the startup-config file + startup_config_path = os.path.join(module_workdir, vm.startup_config) + if os.path.exists(startup_config_path): + try: + with open(startup_config_path, "rb") as f: + content = f.read().decode("utf-8", errors='replace') + if content: + result["startup_config_content"] = content + except OSError as e: + raise DynamipsError("Could not read the startup-config {}: {}".format(startup_config_path, e)) + if private_config_base64: - private_config_content = base64.b64decode(private_config_base64).decode(errors='replace') + private_config_content = base64.b64decode(private_config_base64).decode("utf-8", errors='replace') result["private_config_content"] = private_config_content + else: + # nvram doesn't contain anything if the router has not been started at least once + # in this case just use the private-config file + private_config_path = os.path.join(module_workdir, vm.private_config) + if os.path.exists(private_config_path): + try: + with open(private_config_path, "rb") as f: + content = f.read().decode("utf-8", errors='replace') + if content: + result["private_config_content"] = content + except OSError as e: + raise DynamipsError("Could not read the private-config {}: {}".format(private_config_path, e)) response.set_status(200) response.json(result) diff --git a/gns3server/modules/dynamips/__init__.py b/gns3server/modules/dynamips/__init__.py index 3bbeaf5a..aa95e725 100644 --- a/gns3server/modules/dynamips/__init__.py +++ b/gns3server/modules/dynamips/__init__.py @@ -521,38 +521,32 @@ class Dynamips(BaseManager): default_startup_config_path = os.path.join(module_workdir, "configs", "i{}_startup-config.cfg".format(vm.dynamips_id)) default_private_config_path = os.path.join(module_workdir, "configs", "i{}_private-config.cfg".format(vm.dynamips_id)) - startup_config_content = settings.get("startup_config_content") - if startup_config_content: - startup_config_path = self._create_config(vm, startup_config_content, default_startup_config_path) + startup_config_path = settings.get("startup_config") + if startup_config_path: yield from vm.set_configs(startup_config_path) else: - startup_config_path = settings.get("startup_config") - if startup_config_path: - yield from vm.set_configs(startup_config_path) + startup_config_path = self._create_config(vm, default_startup_config_path, settings.get("startup_config_content")) + yield from vm.set_configs(startup_config_path) - private_config_content = settings.get("private_config_content") - if private_config_content: - private_config_path = self._create_config(vm, private_config_content, default_private_config_path) + private_config_path = settings.get("private_config") + if private_config_path: yield from vm.set_configs(vm.startup_config, private_config_path) else: - private_config_path = settings.get("private_config") - if private_config_path: - yield from vm.set_configs(vm.startup_config, private_config_path) + private_config_path = self._create_config(vm, default_private_config_path, settings.get("private_config_content")) + yield from vm.set_configs(vm.startup_config, private_config_path) - def _create_config(self, vm, content, path): + def _create_config(self, vm, path, content=None): """ Creates a config file. :param vm: VM instance - :param content: config content :param path: path to the destination config file + :param content: config content :returns: relative path to the created config file """ log.info("Creating config file {}".format(path)) - content = "!\n" + content.replace("\r", "") - content = content.replace('%h', vm.name) config_dir = os.path.dirname(path) try: os.makedirs(config_dir, exist_ok=True) @@ -561,7 +555,10 @@ class Dynamips(BaseManager): try: with open(path, "wb") as f: - f.write(content.encode("utf-8")) + if content: + content = "!\n" + content.replace("\r", "") + content = content.replace('%h', vm.name) + f.write(content.encode("utf-8")) except OSError as e: raise DynamipsError("Could not create config file {}: {}".format(path, e)) diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index 77045290..5816d175 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -1436,6 +1436,17 @@ class Router(BaseVM): private_config = private_config.replace("\\", '/') if self._startup_config != startup_config or self._private_config != private_config: + self._startup_config = startup_config + self._private_config = private_config + + module_workdir = self.project.module_working_directory(self.manager.module_name.lower()) + private_config_path = os.path.join(module_workdir, private_config) + try: + if not os.path.getsize(private_config_path): + # an empty private-config can prevent a router to boot. + private_config = '' + except OSError as e: + raise DynamipsError("Cannot access the private-config {}: {}".format(private_config_path, e)) yield from self._hypervisor.send('vm set_config "{name}" "{startup}" "{private}"'.format(name=self._name, startup=startup_config, @@ -1445,15 +1456,11 @@ class Router(BaseVM): id=self._id, startup=startup_config)) - self._startup_config = startup_config - if private_config: log.info('Router "{name}" [{id}]: has a new private-config set: "{private}"'.format(name=self._name, id=self._id, private=private_config)) - self._private_config = private_config - @asyncio.coroutine def extract_config(self): """ diff --git a/gns3server/schemas/dynamips_vm.py b/gns3server/schemas/dynamips_vm.py index 25efd419..2d5de5b9 100644 --- a/gns3server/schemas/dynamips_vm.py +++ b/gns3server/schemas/dynamips_vm.py @@ -745,5 +745,4 @@ VM_CONFIGS_SCHEMA = { }, }, "additionalProperties": False, - "required": ["startup_config_content", "private_config_content"] }