From 99cc7345b892efb00150c58f8b788ad68c02fea2 Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 18 Mar 2014 18:14:30 -0600 Subject: [PATCH] Chassis and private-config support --- gns3server/modules/dynamips/__init__.py | 30 +++++++++++ gns3server/modules/dynamips/backends/vm.py | 57 +++++++++++++-------- gns3server/modules/dynamips/nodes/c7200.py | 18 ++++++- gns3server/modules/dynamips/nodes/router.py | 12 +++-- 4 files changed, 90 insertions(+), 27 deletions(-) diff --git a/gns3server/modules/dynamips/__init__.py b/gns3server/modules/dynamips/__init__.py index 324be5b2..d4ae2030 100644 --- a/gns3server/modules/dynamips/__init__.py +++ b/gns3server/modules/dynamips/__init__.py @@ -20,6 +20,7 @@ Dynamips server module. """ import os +import base64 import tempfile from gns3server.modules import IModule import gns3server.jsonrpc as jsonrpc @@ -362,6 +363,35 @@ class Dynamips(IModule): router.ghost_status = 2 router.ghost_file = ghost_instance + def save_base64config(self, config_base64, router, config_filename): + """ + Saves a base64 encoded config (decoded) to a file. + + :param config_base64: base64 encoded config + :param router: router instance + :param config_filename: file name to save the config + + :returns: relative path to the config file + """ + + config = base64.decodestring(config_base64.encode("utf-8")).decode("utf-8") + config = "!\n" + config.replace("\r", "") + config = config.replace('%h', router.name) + config_dir = os.path.join(router.hypervisor.working_dir, "configs") + if not os.path.exists(config_dir): + try: + os.makedirs(config_dir) + except EnvironmentError as e: + raise DynamipsError("Could not create configs directory: {}".format(e)) + config_path = os.path.join(config_dir, config_filename) + try: + with open(config_path, "w") as f: + log.info("saving startup-config to {}".format(config_path)) + f.write(config) + except EnvironmentError as e: + raise DynamipsError("Could not save the configuration {}: {}".format(config_path, e)) + return "configs" + os.sep + os.path.basename(config_path) + @IModule.route("dynamips.nio.get_interfaces") def nio_get_interfaces(self, request): """ diff --git a/gns3server/modules/dynamips/backends/vm.py b/gns3server/modules/dynamips/backends/vm.py index 2b237cf0..df9f57ab 100644 --- a/gns3server/modules/dynamips/backends/vm.py +++ b/gns3server/modules/dynamips/backends/vm.py @@ -101,6 +101,7 @@ class VM(object): - console (console port number) - aux (auxiliary console port number) - mac_addr (MAC address) + - chassis (router chassis model) Response parameters: - id (vm identifier) @@ -123,6 +124,9 @@ class VM(object): image = request["image"] ram = request["ram"] hypervisor = None + chassis = None + if "chassis" in request: + chassis = request["chassis"] try: @@ -131,7 +135,10 @@ class VM(object): hypervisor = self._hypervisor_manager.allocate_hypervisor_for_router(image, ram) - router = PLATFORMS[platform](hypervisor, name) + if chassis: + router = PLATFORMS[platform](hypervisor, name, chassis=chassis) + else: + router = PLATFORMS[platform](hypervisor, name) router.ram = ram router.image = image router.sparsemem = self._hypervisor_manager.sparse_memory_support @@ -341,6 +348,7 @@ class VM(object): Optional request parameters: - any setting to update - startup_config_base64 (startup-config base64 encoded) + - private_config_base64 (private-config base64 encoded) Response parameters: - same as original request @@ -360,25 +368,18 @@ class VM(object): try: # a new startup-config has been pushed if "startup_config_base64" in request: - config = base64.decodestring(request["startup_config_base64"].encode("utf-8")).decode("utf-8") - config = "!\n" + config.replace("\r", "") - config = config.replace('%h', router.name) - config_dir = os.path.join(router.hypervisor.working_dir, "configs") - if not os.path.exists(config_dir): - try: - os.makedirs(config_dir) - except EnvironmentError as e: - raise DynamipsError("Could not create configs directory: {}".format(e)) - config_path = os.path.join(config_dir, "{}.cfg".format(router.name)) - try: - with open(config_path, "w") as f: - log.info("saving startup-config to {}".format(config_path)) - f.write(config) - except EnvironmentError as e: - raise DynamipsError("Could not save the configuration {}: {}".format(config_path, e)) - request["startup_config"] = "configs" + os.sep + os.path.basename(config_path) + config_filename = "{}.cfg".format(router.name) + request["startup_config"] = self.save_base64config(request["startup_config_base64"], router, config_filename) if "startup_config" in request: router.set_config(request["startup_config"]) + + # a new private-config has been pushed + if "private_config_base64" in request: + config_filename = "{}-private.cfg".format(router.name) + request["private_config"] = self.save_base64config(request["private_config_base64"], router, config_filename) + if "private_config" in request: + router.set_config(router.startup_config, request["private_config"]) + except DynamipsError as e: self.send_custom_error(str(e)) return @@ -455,9 +456,9 @@ class VM(object): router_id = request["id"] router = self._routers[router_id] try: - if router.startup_config: - #TODO: handle private-config - startup_config_base64, _ = router.extract_config() + if router.startup_config or router.private_config: + + startup_config_base64, private_config_base64 = router.extract_config() if startup_config_base64: try: config = base64.decodestring(startup_config_base64.encode("utf-8")).decode("utf-8") @@ -467,7 +468,19 @@ class VM(object): log.info("saving startup-config to {}".format(router.startup_config)) f.write(config) except EnvironmentError as e: - raise DynamipsError("Could not save the configuration {}: {}".format(config_path, e)) + raise DynamipsError("Could not save the startup configuration {}: {}".format(config_path, e)) + + if private_config_base64: + try: + config = base64.decodestring(private_config_base64.encode("utf-8")).decode("utf-8") + config = "!\n" + config.replace("\r", "") + config_path = os.path.join(router.hypervisor.working_dir, router.private_config) + with open(config_path, "w") as f: + log.info("saving private-config to {}".format(router.private_config)) + f.write(config) + except EnvironmentError as e: + raise DynamipsError("Could not save the private configuration {}: {}".format(config_path, e)) + except DynamipsError as e: log.warn("could not save config to {}: {}".format(router.startup_config, e)) diff --git a/gns3server/modules/dynamips/nodes/c7200.py b/gns3server/modules/dynamips/nodes/c7200.py index e83a0b48..0307eedc 100644 --- a/gns3server/modules/dynamips/nodes/c7200.py +++ b/gns3server/modules/dynamips/nodes/c7200.py @@ -86,7 +86,9 @@ class C7200(Router): "disk1": self._disk1, "npe": self._npe, "midplane": self._midplane, - "clock_divisor": self._clock_divisor} + "clock_divisor": self._clock_divisor, + "sensors": self._sensors, + "power_supplies": self._power_supplies} # update the router defaults with the platform specific defaults router_defaults.update(platform_defaults) @@ -230,3 +232,17 @@ class C7200(Router): power_supply_id += 1 self._power_supplies = power_supplies + + def start(self): + """ + Starts this router. + At least the IOS image must be set before starting it. + """ + + # trick: we must send sensors and power supplies info after starting the router + # otherwise they are not taken into account (Dynamips bug?) + Router.start(self) + if self._sensors != [22, 22, 22, 22]: + self.sensors = self._sensors + if self._power_supplies != [1, 1]: + self.power_supplies = self._power_supplies diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index aac9a04d..2c50c747 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -452,11 +452,15 @@ class Router(object): id=self._id, startup='"' + startup_config + '"')) + self._startup_config = startup_config + if private_config: log.info("router {name} [id={id}]: has a private-config set: {private}".format(name=self._name, id=self._id, private='"' + private_config + '"')) + self._private_config = private_config + def extract_config(self): """ Gets the contents of the config files @@ -1180,9 +1184,9 @@ class Router(object): # Generate an OIR event if the router is running and # only for c7200, c3600 and c3745 (NM-4T only) - if self.is_running() and self._platform == 'c7200' \ + if self.is_running() and (self._platform == 'c7200' \ or (self._platform == 'c3600' and self.chassis == '3660') \ - or (self._platform == 'c3745' and adapter == 'NM-4T'): + or (self._platform == 'c3745' and adapter == 'NM-4T')): self._hypervisor.send("vm slot_oir_start {name} {slot_id} 0".format(name=self._name, slot_id=slot_id)) @@ -1212,9 +1216,9 @@ class Router(object): # Generate an OIR event if the router is running and # only for c7200, c3600 and c3745 (NM-4T only) - if self.is_running() and self._platform == 'c7200' \ + if self.is_running() and (self._platform == 'c7200' \ or (self._platform == 'c3600' and self.chassis == '3660') \ - or (self._platform == 'c3745' and adapter == 'NM-4T'): + or (self._platform == 'c3745' and adapter == 'NM-4T')): self._hypervisor.send("vm slot_oir_stop {name} {slot_id} 0".format(name=self._name, slot_id=slot_id))