From 7c99ee9de8ccdd952a439eb7408513a16487ecd9 Mon Sep 17 00:00:00 2001 From: grossmj Date: Thu, 3 Jul 2014 18:56:37 -0600 Subject: [PATCH] New feature: import/export device configs. --- gns3server/modules/dynamips/backends/vm.py | 40 ++++++++++++++++++++++ gns3server/modules/dynamips/schemas/vm.py | 14 ++++++++ gns3server/modules/iou/__init__.py | 38 ++++++++++++++++++++ gns3server/modules/iou/schemas.py | 14 ++++++++ gns3server/modules/vpcs/__init__.py | 38 ++++++++++++++++++++ gns3server/modules/vpcs/schemas.py | 14 ++++++++ setup.py | 2 +- 7 files changed, 159 insertions(+), 1 deletion(-) diff --git a/gns3server/modules/dynamips/backends/vm.py b/gns3server/modules/dynamips/backends/vm.py index f1989e98..d8b3c1e6 100644 --- a/gns3server/modules/dynamips/backends/vm.py +++ b/gns3server/modules/dynamips/backends/vm.py @@ -59,6 +59,7 @@ from ..schemas.vm import VM_UPDATE_SCHEMA from ..schemas.vm import VM_START_CAPTURE_SCHEMA from ..schemas.vm import VM_STOP_CAPTURE_SCHEMA from ..schemas.vm import VM_SAVE_CONFIG_SCHEMA +from ..schemas.vm import VM_EXPORT_CONFIG_SCHEMA from ..schemas.vm import VM_IDLEPCS_SCHEMA from ..schemas.vm import VM_ALLOCATE_UDP_PORT_SCHEMA from ..schemas.vm import VM_ADD_NIO_SCHEMA @@ -617,6 +618,45 @@ class VM(object): except DynamipsError as e: log.warn("could not save config to {}: {}".format(router.startup_config, e)) + @IModule.route("dynamips.vm.export_config") + def vm_export_config(self, request): + """ + Export the config from a router + + Mandatory request parameters: + - id (vm identifier) + + Response parameters: + - startup_config_base64 (startup-config base64 encoded) + - private_config_base64 (private-config base64 encoded) + - False if no configuration can be extracted + """ + + # validate the request + if not self.validate_request(request, VM_EXPORT_CONFIG_SCHEMA): + return + + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: + return + + response = {} + try: + startup_config_base64, private_config_base64 = router.extract_config() + if startup_config_base64: + response["startup_config_base64"] = startup_config_base64 + if private_config_base64: + response["private_config_base64"] = private_config_base64 + except DynamipsError: + self.send_custom_error("unable to extract configs") + return + + if not response: + self.send_response(False) + else: + self.send_response(response) + @IModule.route("dynamips.vm.idlepcs") def vm_idlepcs(self, request): """ diff --git a/gns3server/modules/dynamips/schemas/vm.py b/gns3server/modules/dynamips/schemas/vm.py index 241e059d..3548e8e0 100644 --- a/gns3server/modules/dynamips/schemas/vm.py +++ b/gns3server/modules/dynamips/schemas/vm.py @@ -456,6 +456,20 @@ VM_SAVE_CONFIG_SCHEMA = { "required": ["id"] } +VM_EXPORT_CONFIG_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to export the configs for VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + }, + "additionalProperties": False, + "required": ["id"] +} + VM_IDLEPCS_SCHEMA = { "$schema": "http://json-schema.org/draft-04/schema#", "description": "Request validation to calculate or show idle-pcs for VM instance", diff --git a/gns3server/modules/iou/__init__.py b/gns3server/modules/iou/__init__.py index 2c094b75..63e0a5a8 100644 --- a/gns3server/modules/iou/__init__.py +++ b/gns3server/modules/iou/__init__.py @@ -46,6 +46,7 @@ from .schemas import IOU_ADD_NIO_SCHEMA from .schemas import IOU_DELETE_NIO_SCHEMA from .schemas import IOU_START_CAPTURE_SCHEMA from .schemas import IOU_STOP_CAPTURE_SCHEMA +from .schemas import IOU_EXPORT_CONFIG_SCHEMA import logging log = logging.getLogger(__name__) @@ -755,6 +756,43 @@ class IOU(IModule): response = {"port_id": request["port_id"]} self.send_response(response) + @IModule.route("iou.export_config") + def export_config(self, request): + """ + Exports the initial-config from an IOU instance. + + Mandatory request parameters: + - id (vm identifier) + + Response parameters: + - initial_config_base64 (initial-config base64 encoded) + - False if no configuration can be exported + """ + + # validate the request + if not self.validate_request(request, IOU_EXPORT_CONFIG_SCHEMA): + return + + # get the instance + iou_instance = self.get_iou_instance(request["id"]) + if not iou_instance: + return + + response = {} + initial_config_path = os.path.join(iou_instance.working_dir, iou_instance.initial_config) + try: + with open(initial_config_path, "rb") as f: + config = f.read() + response["initial_config_base64"] = base64.encodebytes(config).decode("utf-8") + except OSError as e: + self.send_custom_error("unable to export the initial-config: {}".format(e)) + return + + if not response: + self.send_response(False) + else: + self.send_response(response) + @IModule.route("iou.echo") def echo(self, request): """ diff --git a/gns3server/modules/iou/schemas.py b/gns3server/modules/iou/schemas.py index 7d317606..10b73e4a 100644 --- a/gns3server/modules/iou/schemas.py +++ b/gns3server/modules/iou/schemas.py @@ -452,3 +452,17 @@ IOU_STOP_CAPTURE_SCHEMA = { "additionalProperties": False, "required": ["id", "slot", "port", "port_id"] } + +IOU_EXPORT_CONFIG_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to export an initial-config from an IOU instance", + "type": "object", + "properties": { + "id": { + "description": "IOU device instance ID", + "type": "integer" + }, + }, + "additionalProperties": False, + "required": ["id"] +} diff --git a/gns3server/modules/vpcs/__init__.py b/gns3server/modules/vpcs/__init__.py index 230f97f1..9d2441d9 100644 --- a/gns3server/modules/vpcs/__init__.py +++ b/gns3server/modules/vpcs/__init__.py @@ -41,6 +41,7 @@ from .schemas import VPCS_RELOAD_SCHEMA from .schemas import VPCS_ALLOCATE_UDP_PORT_SCHEMA from .schemas import VPCS_ADD_NIO_SCHEMA from .schemas import VPCS_DELETE_NIO_SCHEMA +from .schemas import VPCS_EXPORT_CONFIG_SCHEMA import logging log = logging.getLogger(__name__) @@ -597,6 +598,43 @@ class VPCS(IModule): self.send_response(True) + @IModule.route("vpcs.export_config") + def export_config(self, request): + """ + Exports the script file from a VPCS instance. + + Mandatory request parameters: + - id (vm identifier) + + Response parameters: + - script_file_base64 (script file base64 encoded) + - False if no configuration can be exported + """ + + # validate the request + if not self.validate_request(request, VPCS_EXPORT_CONFIG_SCHEMA): + return + + # get the instance + vpcs_instance = self.get_vpcs_instance(request["id"]) + if not vpcs_instance: + return + + response = {} + script_file_path = os.path.join(vpcs_instance.working_dir, vpcs_instance.script_file) + try: + with open(script_file_path, "rb") as f: + config = f.read() + response["script_file_base64"] = base64.encodebytes(config).decode("utf-8") + except OSError as e: + self.send_custom_error("unable to export the script file: {}".format(e)) + return + + if not response: + self.send_response(False) + else: + self.send_response(response) + @IModule.route("vpcs.echo") def echo(self, request): """ diff --git a/gns3server/modules/vpcs/schemas.py b/gns3server/modules/vpcs/schemas.py index d7ca8b87..6556895b 100644 --- a/gns3server/modules/vpcs/schemas.py +++ b/gns3server/modules/vpcs/schemas.py @@ -331,3 +331,17 @@ VPCS_DELETE_NIO_SCHEMA = { "additionalProperties": False, "required": ["id", "port"] } + +VPCS_EXPORT_CONFIG_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to export the script file of a VPCS instance", + "type": "object", + "properties": { + "id": { + "description": "VPCS device instance ID", + "type": "integer" + }, + }, + "additionalProperties": False, + "required": ["id"] +} diff --git a/setup.py b/setup.py index 9008d47a..e64cfa3d 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ setup( install_requires=[ "tornado>=3.1", "pyzmq>=14.0.0", - "jsonschema==2.3.0" + "jsonschema>=2.3.0" ], entry_points={ "console_scripts": [