diff --git a/gns3server/modules/base.py b/gns3server/modules/base.py index 24723ea2..34164f2b 100644 --- a/gns3server/modules/base.py +++ b/gns3server/modules/base.py @@ -26,6 +26,8 @@ import multiprocessing import zmq import signal +from jsonschema import validate, ValidationError + import logging log = logging.getLogger(__name__) @@ -238,6 +240,30 @@ class IModule(multiprocessing.Process): string=str(e), tb=tb)) + def validate_request(self, request, schema): + """ + Validates a request. + + :param request: request (JSON-RPC params) + :param schema: JSON-SCHEMA to validate the request + + :returns: True or False + """ + + # check if we have a request + if request == None: + self.send_param_error() + return False + log.debug("received request {}".format(request)) + + # validate the request + try: + validate(request, schema) + except ValidationError as e: + self.send_custom_error("request validation error: {}".format(e)) + return False + return True + def destinations(self): """ Destinations handled by this module. diff --git a/gns3server/modules/dynamips/__init__.py b/gns3server/modules/dynamips/__init__.py index d87ecaa6..e7944152 100644 --- a/gns3server/modules/dynamips/__init__.py +++ b/gns3server/modules/dynamips/__init__.py @@ -154,6 +154,22 @@ class Dynamips(IModule): self.send_notification("{}.dynamips_stopped".format(self.name), notification) hypervisor.stop() + def get_device_instance(self, device_id, instance_dict): + """ + Returns a device instance. + + :param device_id: device identifier + :param instance_dict: dictionary containing the instances + + :returns: device instance + """ + + if device_id not in instance_dict: + log.debug("device ID {} doesn't exist".format(device_id), exc_info=1) + self.send_custom_error("Device ID {} doesn't exist".format(device_id)) + return None + return instance_dict[device_id] + @IModule.route("dynamips.reset") def reset(self, request): """ @@ -309,34 +325,34 @@ class Dynamips(IModule): #TODO: JSON schema validation nio = None - if request["nio"] == "NIO_UDP": - lport = request["lport"] - rhost = request["rhost"] - rport = request["rport"] + if request["nio"]["type"] == "nio_udp": + lport = request["nio"]["lport"] + rhost = request["nio"]["rhost"] + rport = request["nio"]["rport"] nio = NIO_UDP(node.hypervisor, lport, rhost, rport) -# elif request["nio"] == "NIO_UDP_Auto": +# elif request["nio"] == "nio_udp_auto": # lhost = request["lhost"] # lport_start = request["lport_start"] # lport_end = request["lport_end"] # nio = NIO_UDP_auto(node.hypervisor, lhost, lport_start, lport_end) - elif request["nio"] == "NIO_GenericEthernet": - ethernet_device = request["ethernet_device"] + elif request["nio"]["type"] == "nio_generic_ethernet": + ethernet_device = request["nio"]["ethernet_device"] nio = NIO_GenericEthernet(node.hypervisor, ethernet_device) - elif request["nio"] == "NIO_LinuxEthernet": - ethernet_device = request["ethernet_device"] + elif request["nio"]["type"] == "nio_linux_ethernet": + ethernet_device = request["nio"]["ethernet_device"] nio = NIO_LinuxEthernet(node.hypervisor, ethernet_device) - elif request["nio"] == "NIO_TAP": - tap_device = request["tap_device"] + elif request["nio"]["type"] == "nio_tap": + tap_device = request["nio"]["tap_device"] nio = NIO_TAP(node.hypervisor, tap_device) - elif request["nio"] == "NIO_UNIX": - local_file = request["local_file"] - remote_file = request["remote_file"] + elif request["nio"]["type"] == "nio_unix": + local_file = request["nio"]["local_file"] + remote_file = request["nio"]["remote_file"] nio = NIO_UNIX(node.hypervisor, local_file, remote_file) - elif request["nio"] == "NIO_VDE": - control_file = request["control_file"] - local_file = request["local_file"] + elif request["nio"]["type"] == "nio_vde": + control_file = request["nio"]["control_file"] + local_file = request["nio"]["local_file"] nio = NIO_VDE(node.hypervisor, control_file, local_file) - elif request["nio"] == "NIO_Null": + elif request["nio"]["type"] == "nio_null": nio = NIO_Null(node.hypervisor) return nio @@ -448,8 +464,12 @@ class Dynamips(IModule): :param request: JSON request """ - try: - import netifaces - except ImportError: - raise DynamipsError("The netifaces module is not installed") - self.send_response(netifaces.interfaces()) + response = [] + if not sys.platform.startswith("win"): + try: + import netifaces + except ImportError: + self.send_custom_error("The netifaces module is not installed") + return + response = netifaces.interfaces() + self.send_response(response) diff --git a/gns3server/modules/dynamips/backends/atmsw.py b/gns3server/modules/dynamips/backends/atmsw.py index dc6ff30c..4c5c2644 100644 --- a/gns3server/modules/dynamips/backends/atmsw.py +++ b/gns3server/modules/dynamips/backends/atmsw.py @@ -20,6 +20,13 @@ from gns3server.modules import IModule from ..nodes.atm_switch import ATMSwitch from ..dynamips_error import DynamipsError +from ..schemas.atmsw import ATMSW_CREATE_SCHEMA +from ..schemas.atmsw import ATMSW_DELETE_SCHEMA +from ..schemas.atmsw import ATMSW_UPDATE_SCHEMA +from ..schemas.atmsw import ATMSW_ALLOCATE_UDP_PORT_SCHEMA +from ..schemas.atmsw import ATMSW_ADD_NIO_SCHEMA +from ..schemas.atmsw import ATMSW_DELETE_NIO_SCHEMA + import logging log = logging.getLogger(__name__) @@ -41,7 +48,10 @@ class ATMSW(object): :param request: JSON request """ - #TODO: JSON schema validation for the request + # validate the request + if request and not self.validate_request(request, ATMSW_CREATE_SCHEMA): + return + name = None if request and "name" in request: name = request["name"] @@ -71,22 +81,20 @@ class ATMSW(object): - id (switch identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ATMSW_DELETE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) + # get the ATM switch instance atmsw_id = request["id"] - if atmsw_id not in self._atm_switches: - self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id)) + atmsw = self.get_device_instance(atmsw_id, self._atm_switches) + if not atmsw: return - atmsw = self._atm_switches[atmsw_id] try: atmsw.delete() @@ -95,7 +103,7 @@ class ATMSW(object): except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + self.send_response(True) @IModule.route("dynamips.atmsw.update") def atmsw_update(self, request): @@ -109,32 +117,31 @@ class ATMSW(object): - name (new switch name) Response parameters: - - same as original request + - name if changed :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ATMSW_UPDATE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - atmsw_id = request["id"] - if atmsw_id not in self._atm_switches: - self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id)) + # get the ATM switch instance + atmsw = self.get_device_instance(request["id"], self._atm_switches) + if not atmsw: return - atmsw = self._atm_switches[atmsw_id] + response = {} # rename the switch if requested if "name" in request and atmsw.name != request["name"]: try: atmsw.name = request["name"] + response["name"] = atmsw.name except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + self.send_response(response) @IModule.route("dynamips.atmsw.allocate_udp_port") def atmsw_allocate_udp_port(self, request): @@ -153,17 +160,14 @@ class ATMSW(object): :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ATMSW_ALLOCATE_UDP_PORT_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - atmsw_id = request["id"] - if atmsw_id not in self._atm_switches: - self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id)) + # get the ATM switch instance + atmsw = self.get_device_instance(request["id"], self._atm_switches) + if not atmsw: return - atmsw = self._atm_switches[atmsw_id] try: # allocate a new UDP port @@ -185,42 +189,39 @@ class ATMSW(object): - port (port identifier) - port_id (port identifier) - mappings (VCs/VPs mapped to the port) - - nio (nio type, one of the following) - - "NIO_UDP" + - nio (one of the following) + - type "nio_udp" - lport (local port) - rhost (remote host) - rport (remote port) - - "NIO_GenericEthernet" + - type "nio_generic_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_LinuxEthernet" + - type "nio_linux_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_TAP" + - type "nio_tap" - tap_device (TAP device name e.g. tap0) - - "NIO_UNIX" + - type "nio_unix" - local_file (path to UNIX socket file) - remote_file (path to UNIX socket file) - - "NIO_VDE" + - type "nio_vde" - control_file (path to VDE control file) - local_file (path to VDE local file) - - "NIO_Null" + - type "nio_null" Response parameters: - - same as original request + - port_id (unique port identifier) :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ATMSW_ADD_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - atmsw_id = request["id"] - if atmsw_id not in self._atm_switches: - self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id)) + # get the ATM switch instance + atmsw = self.get_device_instance(request["id"], self._atm_switches) + if not atmsw: return - atmsw = self._atm_switches[atmsw_id] port = request["port"] mappings = request["mappings"] @@ -261,8 +262,7 @@ class ATMSW(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response({"port_id": request["port_id"]}) @IModule.route("dynamips.atmsw.delete_nio") def atmsw_delete_nio(self, request): @@ -274,24 +274,21 @@ class ATMSW(object): - port (port identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ATMSW_DELETE_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - atmsw_id = request["id"] - if atmsw_id not in self._atm_switches: - self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id)) + # get the ATM switch instance + atmsw = self.get_device_instance(request["id"], self._atm_switches) + if not atmsw: return - atmsw = self._atm_switches[atmsw_id] - port = request["port"] + port = request["port"] try: for source, destination in atmsw.mapping.copy().items(): if len(source) == 3 and len(destination) == 3: @@ -315,5 +312,4 @@ class ATMSW(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response(True) diff --git a/gns3server/modules/dynamips/backends/ethhub.py b/gns3server/modules/dynamips/backends/ethhub.py index 68e9852f..28678bf0 100644 --- a/gns3server/modules/dynamips/backends/ethhub.py +++ b/gns3server/modules/dynamips/backends/ethhub.py @@ -19,6 +19,13 @@ from gns3server.modules import IModule from ..nodes.hub import Hub from ..dynamips_error import DynamipsError +from ..schemas.ethhub import ETHHUB_CREATE_SCHEMA +from ..schemas.ethhub import ETHHUB_DELETE_SCHEMA +from ..schemas.ethhub import ETHHUB_UPDATE_SCHEMA +from ..schemas.ethhub import ETHHUB_ALLOCATE_UDP_PORT_SCHEMA +from ..schemas.ethhub import ETHHUB_ADD_NIO_SCHEMA +from ..schemas.ethhub import ETHHUB_DELETE_NIO_SCHEMA + import logging log = logging.getLogger(__name__) @@ -40,7 +47,10 @@ class ETHHUB(object): :param request: JSON request """ - #TODO: JSON schema validation for the request + # validate the request + if request and not self.validate_request(request, ETHHUB_CREATE_SCHEMA): + return + name = None if request and "name" in request: name = request["name"] @@ -70,22 +80,20 @@ class ETHHUB(object): - id (hub identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHHUB_DELETE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) + # get the Ethernet hub instance ethhub_id = request["id"] - if ethhub_id not in self._ethernet_hubs: - self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id)) + ethhub = self.get_device_instance(ethhub_id, self._ethernet_hubs) + if not ethhub: return - ethhub = self._ethernet_hubs[ethhub_id] try: ethhub.delete() @@ -108,27 +116,26 @@ class ETHHUB(object): - name (new hub name) Response parameters: - - same as original request + - name if changed :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHHUB_UPDATE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - ethhub_id = request["id"] - if ethhub_id not in self._ethernet_hubs: - self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id)) + # get the Ethernet hub instance + ethhub = self.get_device_instance(request["id"], self._ethernet_hubs) + if not ethhub: return - ethhub = self._ethernet_hubs[ethhub_id] + response = {} # rename the hub if requested if "name" in request and ethhub.name != request["name"]: try: ethhub.name = request["name"] + response["name"] = ethhub.name except DynamipsError as e: self.send_custom_error(str(e)) return @@ -152,17 +159,14 @@ class ETHHUB(object): :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHHUB_ALLOCATE_UDP_PORT_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - ethhub_id = request["id"] - if ethhub_id not in self._ethernet_hubs: - self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id)) + # get the Ethernet hub instance + ethhub = self.get_device_instance(request["id"], self._ethernet_hubs) + if not ethhub: return - ethhub = self._ethernet_hubs[ethhub_id] try: # allocate a new UDP port @@ -183,44 +187,41 @@ class ETHHUB(object): - id (hub identifier) - port (port identifier) - port_id (port identifier) - - nio (nio type, one of the following) - - "NIO_UDP" + - nio (one of the following) + - type "nio_udp" - lport (local port) - rhost (remote host) - rport (remote port) - - "NIO_GenericEthernet" + - type "nio_generic_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_LinuxEthernet" + - type "nio_linux_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_TAP" + - type "nio_tap" - tap_device (TAP device name e.g. tap0) - - "NIO_UNIX" + - type "nio_unix" - local_file (path to UNIX socket file) - remote_file (path to UNIX socket file) - - "NIO_VDE" + - type "nio_vde" - control_file (path to VDE control file) - local_file (path to VDE local file) - - "NIO_Null" + - type "nio_null" Response parameters: - - same as original request + - port_id (unique port identifier) :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHHUB_ADD_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - ethhub_id = request["id"] - if ethhub_id not in self._ethernet_hubs: - self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id)) + # get the Ethernet hub instance + ethhub = self.get_device_instance(request["id"], self._ethernet_hubs) + if not ethhub: return - ethhub = self._ethernet_hubs[ethhub_id] - port = request["port"] + port = request["port"] try: nio = self.create_nio(ethhub, request) if not nio: @@ -235,8 +236,7 @@ class ETHHUB(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response({"port_id": request["port_id"]}) @IModule.route("dynamips.ethhub.delete_nio") def ethsw_delete_nio(self, request): @@ -248,24 +248,21 @@ class ETHHUB(object): - port (port identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHHUB_DELETE_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - ethhub_id = request["id"] - if ethhub_id not in self._ethernet_hubs: - self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id)) + # get the Ethernet hub instance + ethhub = self.get_device_instance(request["id"], self._ethernet_hubs) + if not ethhub: return - ethhub = self._ethernet_hubs[ethhub_id] - port = request["port"] + port = request["port"] try: nio = ethhub.remove_nio(port) nio.delete() @@ -273,5 +270,4 @@ class ETHHUB(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response(True) diff --git a/gns3server/modules/dynamips/backends/ethsw.py b/gns3server/modules/dynamips/backends/ethsw.py index 316258ad..cf8369f4 100644 --- a/gns3server/modules/dynamips/backends/ethsw.py +++ b/gns3server/modules/dynamips/backends/ethsw.py @@ -19,6 +19,13 @@ from gns3server.modules import IModule from ..nodes.ethernet_switch import EthernetSwitch from ..dynamips_error import DynamipsError +from ..schemas.ethsw import ETHSW_CREATE_SCHEMA +from ..schemas.ethsw import ETHSW_DELETE_SCHEMA +from ..schemas.ethsw import ETHSW_UPDATE_SCHEMA +from ..schemas.ethsw import ETHSW_ALLOCATE_UDP_PORT_SCHEMA +from ..schemas.ethsw import ETHSW_ADD_NIO_SCHEMA +from ..schemas.ethsw import ETHSW_DELETE_NIO_SCHEMA + import logging log = logging.getLogger(__name__) @@ -40,7 +47,10 @@ class ETHSW(object): :param request: JSON request """ - #TODO: JSON schema validation for the request + # validate the request + if request and not self.validate_request(request, ETHSW_CREATE_SCHEMA): + return + name = None if request and "name" in request: name = request["name"] @@ -70,22 +80,20 @@ class ETHSW(object): - id (switch identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHSW_DELETE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) + # get the Ethernet switch instance ethsw_id = request["id"] - if ethsw_id not in self._ethernet_switches: - self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id)) + ethsw = self.get_device_instance(ethsw_id, self._ethernet_switches) + if not ethsw: return - ethsw = self._ethernet_switches[ethsw_id] try: ethsw.delete() @@ -94,7 +102,7 @@ class ETHSW(object): except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + self.send_response(True) @IModule.route("dynamips.ethsw.update") def ethsw_update(self, request): @@ -109,22 +117,19 @@ class ETHSW(object): - ports (ports settings) Response parameters: - - same as original request + - name if changed :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHSW_UPDATE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - ethsw_id = request["id"] - if ethsw_id not in self._ethernet_switches: - self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id)) + # get the Ethernet switch instance + ethsw = self.get_device_instance(request["id"], self._ethernet_switches) + if not ethsw: return - ethsw = self._ethernet_switches[ethsw_id] if "ports" in request: ports = request["ports"] @@ -144,15 +149,17 @@ class ETHSW(object): self.send_custom_error(str(e)) return + response = {} # rename the switch if requested if "name" in request and ethsw.name != request["name"]: try: ethsw.name = request["name"] + response["name"] = ethsw.name except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + self.send_response(response) @IModule.route("dynamips.ethsw.allocate_udp_port") def ethsw_allocate_udp_port(self, request): @@ -171,17 +178,14 @@ class ETHSW(object): :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHSW_ALLOCATE_UDP_PORT_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - ethsw_id = request["id"] - if ethsw_id not in self._ethernet_switches: - self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id)) + # get the Ethernet switch instance + ethsw = self.get_device_instance(request["id"], self._ethernet_switches) + if not ethsw: return - ethsw = self._ethernet_switches[ethsw_id] try: # allocate a new UDP port @@ -204,42 +208,39 @@ class ETHSW(object): - port_id (port identifier) - vlan (vlan identifier) - port_type ("access", "dot1q" or "qinq") - - nio (nio type, one of the following) - - "NIO_UDP" + - nio (one of the following) + - type "nio_udp" - lport (local port) - rhost (remote host) - rport (remote port) - - "NIO_GenericEthernet" + - type "nio_generic_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_LinuxEthernet" + - type "nio_linux_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_TAP" + - type "nio_tap" - tap_device (TAP device name e.g. tap0) - - "NIO_UNIX" + - type "nio_unix" - local_file (path to UNIX socket file) - remote_file (path to UNIX socket file) - - "NIO_VDE" + - type "nio_vde" - control_file (path to VDE control file) - local_file (path to VDE local file) - - "NIO_Null" + - type "nio_null" Response parameters: - - same as original request + - port_id (unique port identifier) :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHSW_ADD_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - ethsw_id = request["id"] - if ethsw_id not in self._ethernet_switches: - self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id)) + # get the Ethernet switch instance + ethsw = self.get_device_instance(request["id"], self._ethernet_switches) + if not ethsw: return - ethsw = self._ethernet_switches[ethsw_id] port = request["port"] vlan = request["vlan"] @@ -264,8 +265,7 @@ class ETHSW(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response({"port_id": request["port_id"]}) @IModule.route("dynamips.ethsw.delete_nio") def ethsw_delete_nio(self, request): @@ -277,24 +277,21 @@ class ETHSW(object): - port (port identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, ETHSW_DELETE_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - ethsw_id = request["id"] - if ethsw_id not in self._ethernet_switches: - self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id)) + # get the Ethernet switch instance + ethsw = self.get_device_instance(request["id"], self._ethernet_switches) + if not ethsw: return - ethsw = self._ethernet_switches[ethsw_id] - port = request["port"] + port = request["port"] try: nio = ethsw.remove_nio(port) nio.delete() @@ -302,5 +299,4 @@ class ETHSW(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response(True) diff --git a/gns3server/modules/dynamips/backends/frsw.py b/gns3server/modules/dynamips/backends/frsw.py index 3432d47e..5bbf72a2 100644 --- a/gns3server/modules/dynamips/backends/frsw.py +++ b/gns3server/modules/dynamips/backends/frsw.py @@ -19,6 +19,13 @@ from gns3server.modules import IModule from ..nodes.frame_relay_switch import FrameRelaySwitch from ..dynamips_error import DynamipsError +from ..schemas.frsw import FRSW_CREATE_SCHEMA +from ..schemas.frsw import FRSW_DELETE_SCHEMA +from ..schemas.frsw import FRSW_UPDATE_SCHEMA +from ..schemas.frsw import FRSW_ALLOCATE_UDP_PORT_SCHEMA +from ..schemas.frsw import FRSW_ADD_NIO_SCHEMA +from ..schemas.frsw import FRSW_DELETE_NIO_SCHEMA + import logging log = logging.getLogger(__name__) @@ -40,7 +47,10 @@ class FRSW(object): :param request: JSON request """ - #TODO: JSON schema validation for the request + # validate the request + if request and not self.validate_request(request, FRSW_CREATE_SCHEMA): + return + name = None if request and "name" in request: name = request["name"] @@ -70,22 +80,20 @@ class FRSW(object): - id (switch identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, FRSW_DELETE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) + # get the Frame relay switch instance frsw_id = request["id"] - if frsw_id not in self._frame_relay_switches: - self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id)) + frsw = self.get_device_instance(frsw_id, self._frame_relay_switches) + if not frsw: return - frsw = self._frame_relay_switches[frsw_id] try: frsw.delete() @@ -94,7 +102,8 @@ class FRSW(object): except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + + self.send_response(True) @IModule.route("dynamips.frsw.update") def frsw_update(self, request): @@ -108,30 +117,30 @@ class FRSW(object): - name (new switch name) Response parameters: - - same as original request + - name if updated :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, FRSW_UPDATE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - frsw_id = request["id"] - if frsw_id not in self._frame_relay_switches: - self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id)) + # get the Frame relay switch instance + frsw = self.get_device_instance(request["id"], self._frame_relay_switches) + if not frsw: return - frsw = self._frame_relay_switches[frsw_id] + response = {} # rename the switch if requested if "name" in request and frsw.name != request["name"]: try: frsw.name = request["name"] + response["name"] = frsw.name except DynamipsError as e: self.send_custom_error(str(e)) return + self.send_response(request) @IModule.route("dynamips.frsw.allocate_udp_port") @@ -151,17 +160,14 @@ class FRSW(object): :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, FRSW_ALLOCATE_UDP_PORT_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - frsw_id = request["id"] - if frsw_id not in self._frame_relay_switches: - self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id)) + # get the Frame relay switch instance + frsw = self.get_device_instance(request["id"], self._frame_relay_switches) + if not frsw: return - frsw = self._frame_relay_switches[frsw_id] try: # allocate a new UDP port @@ -183,42 +189,39 @@ class FRSW(object): - port (port identifier) - port_id (port identifier) - mappings (VCs mapped to the port) - - nio (nio type, one of the following) - - "NIO_UDP" + - nio (one of the following) + - type "nio_udp" - lport (local port) - rhost (remote host) - rport (remote port) - - "NIO_GenericEthernet" + - type "nio_generic_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_LinuxEthernet" + - type "nio_linux_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_TAP" + - type "nio_tap" - tap_device (TAP device name e.g. tap0) - - "NIO_UNIX" + - type "nio_unix" - local_file (path to UNIX socket file) - remote_file (path to UNIX socket file) - - "NIO_VDE" + - type "nio_vde" - control_file (path to VDE control file) - local_file (path to VDE local file) - - "NIO_Null" + - type "nio_null" Response parameters: - - same as original request + - port_id (unique port identifier) :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, FRSW_ADD_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - frsw_id = request["id"] - if frsw_id not in self._frame_relay_switches: - self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id)) + # get the Frame relay switch instance + frsw = self.get_device_instance(request["id"], self._frame_relay_switches) + if not frsw: return - frsw = self._frame_relay_switches[frsw_id] port = request["port"] mappings = request["mappings"] @@ -246,8 +249,7 @@ class FRSW(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response({"port_id": request["port_id"]}) @IModule.route("dynamips.frsw.delete_nio") def frsw_delete_nio(self, request): @@ -259,24 +261,21 @@ class FRSW(object): - port (port identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, FRSW_DELETE_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - frsw_id = request["id"] - if frsw_id not in self._frame_relay_switches: - self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id)) + # get the Frame relay switch instance + frsw = self.get_device_instance(request["id"], self._frame_relay_switches) + if not frsw: return - frsw = self._frame_relay_switches[frsw_id] - port = request["port"] + port = request["port"] try: # remove the VCs mapped with this port/nio for source, destination in frsw.mapping.copy().items(): @@ -292,5 +291,4 @@ class FRSW(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response(True) diff --git a/gns3server/modules/dynamips/backends/vm.py b/gns3server/modules/dynamips/backends/vm.py index 9e21c8bb..3a838788 100644 --- a/gns3server/modules/dynamips/backends/vm.py +++ b/gns3server/modules/dynamips/backends/vm.py @@ -49,6 +49,19 @@ from ..adapters.wic_1enet import WIC_1ENET from ..adapters.wic_1t import WIC_1T from ..adapters.wic_2t import WIC_2T +from ..schemas.vm import VM_CREATE_SCHEMA +from ..schemas.vm import VM_DELETE_SCHEMA +from ..schemas.vm import VM_START_SCHEMA +from ..schemas.vm import VM_STOP_SCHEMA +from ..schemas.vm import VM_SUSPEND_SCHEMA +from ..schemas.vm import VM_RELOAD_SCHEMA +from ..schemas.vm import VM_UPDATE_SCHEMA +from ..schemas.vm import VM_SAVE_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 +from ..schemas.vm import VM_DELETE_NIO_SCHEMA + import logging log = logging.getLogger(__name__) @@ -110,13 +123,10 @@ class VM(object): :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_CREATE_SCHEMA): return - log.debug("received request {}".format(request)) - - #TODO: JSON schema validation name = None if "name" in request: name = request["name"] @@ -130,6 +140,9 @@ class VM(object): try: + if platform not in PLATFORMS: + raise DynamipsError("Unknown router platform: {}".format(platform)) + if not self._hypervisor_manager: self.start_hypervisor_manager() @@ -197,22 +210,20 @@ class VM(object): - id (vm identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_DELETE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) + # get the router instance router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + router = self.get_device_instance(router_id, self._routers) + if not router: return - router = self._routers[router_id] try: router.delete() @@ -221,7 +232,8 @@ class VM(object): except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + + self.send_response(True) @IModule.route("dynamips.vm.start") def vm_start(self, request): @@ -232,29 +244,26 @@ class VM(object): - id (vm identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_START_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return - router = self._routers[router_id] try: router.start() except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + self.send_response(True) @IModule.route("dynamips.vm.stop") def vm_stop(self, request): @@ -265,29 +274,27 @@ class VM(object): - id (vm identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_STOP_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return - router = self._routers[router_id] try: router.stop() except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + + self.send_response(True) @IModule.route("dynamips.vm.suspend") def vm_suspend(self, request): @@ -298,29 +305,27 @@ class VM(object): - id (vm identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_SUSPEND_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return - router = self._routers[router_id] try: router.suspend() except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + + self.send_response(True) @IModule.route("dynamips.vm.reload") def vm_reload(self, request): @@ -331,22 +336,20 @@ class VM(object): - id (vm identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_RELOAD_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return - router = self._routers[router_id] + try: if router.get_status() != "inactive": router.stop() @@ -354,7 +357,8 @@ class VM(object): except DynamipsError as e: self.send_custom_error(str(e)) return - self.send_response(request) + + self.send_response(True) @IModule.route("dynamips.vm.update") def vm_update(self, request): @@ -370,37 +374,35 @@ class VM(object): - private_config_base64 (private-config base64 encoded) Response parameters: - - same as original request + - updated settings :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_UPDATE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return - router = self._routers[router_id] + response = {} try: # a new startup-config has been pushed if "startup_config_base64" in request: 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"]) + response["startup_config"] = self.save_base64config(request["startup_config_base64"], router, config_filename) + if "startup_config" in response: + router.set_config(response["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"]) + response["private_config"] = self.save_base64config(request["private_config_base64"], router, config_filename) + if "private_config" in response: + router.set_config(router.startup_config, response["private_config"]) except DynamipsError as e: self.send_custom_error(str(e)) @@ -411,6 +413,7 @@ class VM(object): if hasattr(router, name) and getattr(router, name) != value: try: setattr(router, name, value) + response[name] = value except DynamipsError as e: self.send_custom_error(str(e)) return @@ -422,6 +425,7 @@ class VM(object): if router.slots[slot_id] and type(router.slots[slot_id]) != type(adapter): router.slot_remove_binding(slot_id) router.slot_add_binding(slot_id, adapter) + response[name] = value except DynamipsError as e: self.send_custom_error(str(e)) return @@ -430,6 +434,7 @@ class VM(object): if router.slots[slot_id]: try: router.slot_remove_binding(slot_id) + response[name] = value except DynamipsError as e: self.send_custom_error(str(e)) return @@ -441,6 +446,7 @@ class VM(object): if router.slots[0].wics[wic_slot_id] and type(router.slots[0].wics[wic_slot_id]) != type(wic): router.uninstall_wic(wic_slot_id) router.install_wic(wic_slot_id, wic) + response[name] = value except DynamipsError as e: self.send_custom_error(str(e)) return @@ -449,6 +455,7 @@ class VM(object): if router.slots[0].wics and router.slots[0].wics[wic_slot_id]: try: router.uninstall_wic(wic_slot_id) + response[name] = value except DynamipsError as e: self.send_custom_error(str(e)) return @@ -457,8 +464,7 @@ class VM(object): if self._hypervisor_manager.ghost_ios_support: self.set_ghost_ios(router) - # for now send back the original request - self.send_response(request) + self.send_response(response) @IModule.route("dynamips.vm.save_config") def vm_save_config(self, request): @@ -469,17 +475,14 @@ class VM(object): - id (vm identifier) """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_SAVE_CONFIG_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return - router = self._routers[router_id] try: if router.startup_config or router.private_config: @@ -528,17 +531,14 @@ class VM(object): :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_IDLEPCS_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return - router = self._routers[router_id] try: if "compute" in request and request["compute"] == False: @@ -551,7 +551,7 @@ class VM(object): self.send_custom_error(str(e)) return - response = {"id": router_id, + response = {"id": router.id, "idlepcs": idlepcs} self.send_response(response) @@ -571,17 +571,14 @@ class VM(object): :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_ALLOCATE_UDP_PORT_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return - router = self._routers[router_id] try: # allocate a new UDP port @@ -603,46 +600,42 @@ class VM(object): - slot (slot number) - port (port number) - port_id (unique port identifier) - - nio (nio type, one of the following) - - "NIO_UDP" + - nio (one of the following) + - type "nio_udp" - lport (local port) - rhost (remote host) - rport (remote port) - - "NIO_GenericEthernet" + - type "nio_generic_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_LinuxEthernet" + - type "nio_linux_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_TAP" + - type "nio_tap" - tap_device (TAP device name e.g. tap0) - - "NIO_UNIX" + - type "nio_unix" - local_file (path to UNIX socket file) - remote_file (path to UNIX socket file) - - "NIO_VDE" + - type "nio_vde" - control_file (path to VDE control file) - local_file (path to VDE local file) - - "NIO_Null" + - type "nio_null" Response parameters: - - same as original request + - port_id (unique port identifier) :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_ADD_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return - router = self._routers[router_id] slot = request["slot"] port = request["port"] - try: nio = self.create_nio(router, request) if not nio: @@ -657,8 +650,7 @@ class VM(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response({"port_id": request["port_id"]}) @IModule.route("dynamips.vm.delete_nio") def vm_delete_nio(self, request): @@ -671,25 +663,22 @@ class VM(object): - port (port identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, VM_DELETE_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - router_id = request["id"] - router = self._routers[router_id] - if router_id not in self._routers: - self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) + # get the router instance + router = self.get_device_instance(request["id"], self._routers) + if not router: return + slot = request["slot"] port = request["port"] - try: nio = router.slot_remove_nio_binding(slot, port) nio.delete() @@ -697,5 +686,4 @@ class VM(object): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response(True) diff --git a/gns3server/modules/dynamips/schemas/__init__.py b/gns3server/modules/dynamips/schemas/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gns3server/modules/dynamips/schemas/atmsw.py b/gns3server/modules/dynamips/schemas/atmsw.py new file mode 100644 index 00000000..5d96e8c5 --- /dev/null +++ b/gns3server/modules/dynamips/schemas/atmsw.py @@ -0,0 +1,259 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2014 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +ATMSW_CREATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to create a new ATM switch instance", + "type": "object", + "properties": { + "name": { + "description": "ATM switch name", + "type": "string", + "minLength": 1, + } + } +} + +ATMSW_DELETE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete an ATM switch instance", + "type": "object", + "properties": { + "id": { + "description": "ATM switch instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +ATMSW_UPDATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to update an ATM switch instance", + "type": "object", + "properties": { + "id": { + "description": "ATM switch instance ID", + "type": "integer" + }, + "name": { + "description": "ATM switch name", + "type": "string", + "minLength": 1, + }, + }, + "required": ["id"] +} + +ATMSW_ALLOCATE_UDP_PORT_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to allocate an UDP port for an ATM switch instance", + "type": "object", + "properties": { + "id": { + "description": "ATM switch instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the ATM switch instance", + "type": "integer" + }, + }, + "required": ["id", "port_id"] +} + +ATMSW_ADD_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to add a NIO for an ATM switch instance", + "type": "object", + + "definitions": { + "UDP": { + "description": "UDP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_udp"] + }, + "lport": { + "description": "Local port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "rhost": { + "description": "Remote host", + "type": "string", + "minLength": 1 + }, + "rport": { + "description": "Remote port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + } + }, + "required": ["type", "lport", "rhost", "rport"], + "additionalProperties": False + }, + "Ethernet": { + "description": "Generic Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_generic_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "LinuxEthernet": { + "description": "Linux Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_linux_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "TAP": { + "description": "TAP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_tap"] + }, + "tap_device": { + "description": "TAP device name e.g. tap0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "tap_device"], + "additionalProperties": False + }, + "UNIX": { + "description": "UNIX Network Input/Output", + "properties": { + "type": { + "enum": ["nio_unix"] + }, + "local_file": { + "description": "path to the UNIX socket file (local)", + "type": "string", + "minLength": 1 + }, + "remote_file": { + "description": "path to the UNIX socket file (remote)", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "local_file", "remote_file"], + "additionalProperties": False + }, + "VDE": { + "description": "VDE Network Input/Output", + "properties": { + "type": { + "enum": ["nio_vde"] + }, + "control_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + "local_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "control_file", "local_file"], + "additionalProperties": False + }, + "NULL": { + "description": "NULL Network Input/Output", + "properties": { + "type": { + "enum": ["nio_null"] + }, + }, + "required": ["type"], + "additionalProperties": False + }, + }, + + "properties": { + "id": { + "description": "ATM switch instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the ATM switch instance", + "type": "integer" + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 1, + }, + "mappings": { + "type": "object", + }, + "nio": { + "type": "object", + "description": "Network Input/Output", + "oneOf": [ + {"$ref": "#/definitions/UDP"}, + {"$ref": "#/definitions/Ethernet"}, + {"$ref": "#/definitions/LinuxEthernet"}, + {"$ref": "#/definitions/TAP"}, + {"$ref": "#/definitions/UNIX"}, + {"$ref": "#/definitions/VDE"}, + {"$ref": "#/definitions/NULL"}, + ] + }, + }, + "required": ["id", "port", "port_id", "mappings", "nio"], +} + +ATMSW_DELETE_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete a NIO for an ATM switch instance", + "type": "object", + "properties": { + "id": { + "description": "ATM switch instance ID", + "type": "integer" + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 1, + }, + }, + "required": ["id", "port"] +} diff --git a/gns3server/modules/dynamips/schemas/ethhub.py b/gns3server/modules/dynamips/schemas/ethhub.py new file mode 100644 index 00000000..db1b1a29 --- /dev/null +++ b/gns3server/modules/dynamips/schemas/ethhub.py @@ -0,0 +1,256 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2014 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +ETHHUB_CREATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to create a new Ethernet hub instance", + "type": "object", + "properties": { + "name": { + "description": "Ethernet hub name", + "type": "string", + "minLength": 1, + } + } +} + +ETHHUB_DELETE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete an Ethernet hub instance", + "type": "object", + "properties": { + "id": { + "description": "Ethernet hub instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +ETHHUB_UPDATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to update an Ethernet hub instance", + "type": "object", + "properties": { + "id": { + "description": "Ethernet hub instance ID", + "type": "integer" + }, + "name": { + "description": "Ethernet hub name", + "type": "string", + "minLength": 1, + }, + }, + "required": ["id"] +} + +ETHHUB_ALLOCATE_UDP_PORT_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to allocate an UDP port for an Ethernet hub instance", + "type": "object", + "properties": { + "id": { + "description": "Ethernet hub instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the Ethernet hub instance", + "type": "integer" + }, + }, + "required": ["id", "port_id"] +} + +ETHHUB_ADD_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to add a NIO for an Ethernet hub instance", + "type": "object", + + "definitions": { + "UDP": { + "description": "UDP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_udp"] + }, + "lport": { + "description": "Local port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "rhost": { + "description": "Remote host", + "type": "string", + "minLength": 1 + }, + "rport": { + "description": "Remote port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + } + }, + "required": ["type", "lport", "rhost", "rport"], + "additionalProperties": False + }, + "Ethernet": { + "description": "Generic Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_generic_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "LinuxEthernet": { + "description": "Linux Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_linux_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "TAP": { + "description": "TAP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_tap"] + }, + "tap_device": { + "description": "TAP device name e.g. tap0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "tap_device"], + "additionalProperties": False + }, + "UNIX": { + "description": "UNIX Network Input/Output", + "properties": { + "type": { + "enum": ["nio_unix"] + }, + "local_file": { + "description": "path to the UNIX socket file (local)", + "type": "string", + "minLength": 1 + }, + "remote_file": { + "description": "path to the UNIX socket file (remote)", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "local_file", "remote_file"], + "additionalProperties": False + }, + "VDE": { + "description": "VDE Network Input/Output", + "properties": { + "type": { + "enum": ["nio_vde"] + }, + "control_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + "local_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "control_file", "local_file"], + "additionalProperties": False + }, + "NULL": { + "description": "NULL Network Input/Output", + "properties": { + "type": { + "enum": ["nio_null"] + }, + }, + "required": ["type"], + "additionalProperties": False + }, + }, + + "properties": { + "id": { + "description": "Ethernet hub instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the Ethernet hub instance", + "type": "integer" + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 1, + }, + "nio": { + "type": "object", + "description": "Network Input/Output", + "oneOf": [ + {"$ref": "#/definitions/UDP"}, + {"$ref": "#/definitions/Ethernet"}, + {"$ref": "#/definitions/LinuxEthernet"}, + {"$ref": "#/definitions/TAP"}, + {"$ref": "#/definitions/UNIX"}, + {"$ref": "#/definitions/VDE"}, + {"$ref": "#/definitions/NULL"}, + ] + }, + }, + "required": ["id", "port_id", "port", "nio"] +} + +ETHHUB_DELETE_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete a NIO for an Ethernet hub instance", + "type": "object", + "properties": { + "id": { + "description": "Ethernet hub instance ID", + "type": "integer" + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 1, + }, + }, + "required": ["id", "port"] +} diff --git a/gns3server/modules/dynamips/schemas/ethsw.py b/gns3server/modules/dynamips/schemas/ethsw.py new file mode 100644 index 00000000..c68a3565 --- /dev/null +++ b/gns3server/modules/dynamips/schemas/ethsw.py @@ -0,0 +1,285 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2014 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +ETHSW_CREATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to create a new Ethernet switch instance", + "type": "object", + "properties": { + "name": { + "description": "Ethernet switch name", + "type": "string", + "minLength": 1, + } + } +} + +ETHSW_DELETE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete an Ethernet switch instance", + "type": "object", + "properties": { + "id": { + "description": "Ethernet switch instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +#TODO: ports {'1': {'vlan': 1, 'type': 'qinq'} +ETHSW_UPDATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to update an Ethernet switch instance", + "type": "object", + "properties": { + "id": { + "description": "Ethernet switch instance ID", + "type": "integer" + }, + "name": { + "description": "Ethernet switch name", + "type": "string", + "minLength": 1, + }, +# "ports": { +# "type": "object", +# "properties": { +# "type": { +# "description": "Port type", +# "enum": ["access", "dot1q", "qinq"], +# }, +# "vlan": { +# "description": "VLAN number", +# "type": "integer", +# "minimum": 1 +# }, +# }, +# }, + }, + "required": ["id"] +} + +ETHSW_ALLOCATE_UDP_PORT_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to allocate an UDP port for an Ethernet switch instance", + "type": "object", + "properties": { + "id": { + "description": "Ethernet switch instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the Ethernet switch instance", + "type": "integer" + }, + }, + "required": ["id", "port_id"] +} + +ETHSW_ADD_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to add a NIO for an Ethernet switch instance", + "type": "object", + + "definitions": { + "UDP": { + "description": "UDP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_udp"] + }, + "lport": { + "description": "Local port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "rhost": { + "description": "Remote host", + "type": "string", + "minLength": 1 + }, + "rport": { + "description": "Remote port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + } + }, + "required": ["type", "lport", "rhost", "rport"], + "additionalProperties": False + }, + "Ethernet": { + "description": "Generic Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_generic_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "LinuxEthernet": { + "description": "Linux Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_linux_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "TAP": { + "description": "TAP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_tap"] + }, + "tap_device": { + "description": "TAP device name e.g. tap0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "tap_device"], + "additionalProperties": False + }, + "UNIX": { + "description": "UNIX Network Input/Output", + "properties": { + "type": { + "enum": ["nio_unix"] + }, + "local_file": { + "description": "path to the UNIX socket file (local)", + "type": "string", + "minLength": 1 + }, + "remote_file": { + "description": "path to the UNIX socket file (remote)", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "local_file", "remote_file"], + "additionalProperties": False + }, + "VDE": { + "description": "VDE Network Input/Output", + "properties": { + "type": { + "enum": ["nio_vde"] + }, + "control_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + "local_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "control_file", "local_file"], + "additionalProperties": False + }, + "NULL": { + "description": "NULL Network Input/Output", + "properties": { + "type": { + "enum": ["nio_null"] + }, + }, + "required": ["type"], + "additionalProperties": False + }, + }, + + "properties": { + "id": { + "description": "Ethernet switch instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the Ethernet switch instance", + "type": "integer" + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 1, + }, + "port_type": { + "description": "Port type", + "enum": ["access", "dot1q", "qinq"], + }, + "vlan": { + "description": "VLAN number", + "type": "integer", + "minimum": 1 + }, + "nio": { + "type": "object", + "description": "Network Input/Output", + "oneOf": [ + {"$ref": "#/definitions/UDP"}, + {"$ref": "#/definitions/Ethernet"}, + {"$ref": "#/definitions/LinuxEthernet"}, + {"$ref": "#/definitions/TAP"}, + {"$ref": "#/definitions/UNIX"}, + {"$ref": "#/definitions/VDE"}, + {"$ref": "#/definitions/NULL"}, + ] + }, + }, + "required": ["id", "port_id", "port", "port_type", "vlan", "nio"], + + "dependencies": { + "port_type": ["vlan"], + "vlan": ["port_type"] + } +} + +ETHSW_DELETE_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete a NIO for an Ethernet switch instance", + "type": "object", + "properties": { + "id": { + "description": "Ethernet switch instance ID", + "type": "integer" + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 1, + }, + }, + "required": ["id", "port"] +} diff --git a/gns3server/modules/dynamips/schemas/frsw.py b/gns3server/modules/dynamips/schemas/frsw.py new file mode 100644 index 00000000..984d2c24 --- /dev/null +++ b/gns3server/modules/dynamips/schemas/frsw.py @@ -0,0 +1,259 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2014 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +FRSW_CREATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to create a new Frame relay switch instance", + "type": "object", + "properties": { + "name": { + "description": "Frame relay switch name", + "type": "string", + "minLength": 1, + } + } +} + +FRSW_DELETE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete a Frame relay switch instance", + "type": "object", + "properties": { + "id": { + "description": "Frame relay switch instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +FRSW_UPDATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to update a Frame relay switch instance", + "type": "object", + "properties": { + "id": { + "description": "Frame relay switch instance ID", + "type": "integer" + }, + "name": { + "description": "Frame relay switch name", + "type": "string", + "minLength": 1, + }, + }, + "required": ["id"] +} + +FRSW_ALLOCATE_UDP_PORT_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to allocate an UDP port for a Frame relay switch instance", + "type": "object", + "properties": { + "id": { + "description": "Frame relay switch instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the Frame relay switch instance", + "type": "integer" + }, + }, + "required": ["id", "port_id"] +} + +FRSW_ADD_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to add a NIO for a Frame relay switch instance", + "type": "object", + + "definitions": { + "UDP": { + "description": "UDP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_udp"] + }, + "lport": { + "description": "Local port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "rhost": { + "description": "Remote host", + "type": "string", + "minLength": 1 + }, + "rport": { + "description": "Remote port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + } + }, + "required": ["type", "lport", "rhost", "rport"], + "additionalProperties": False + }, + "Ethernet": { + "description": "Generic Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_generic_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "LinuxEthernet": { + "description": "Linux Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_linux_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "TAP": { + "description": "TAP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_tap"] + }, + "tap_device": { + "description": "TAP device name e.g. tap0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "tap_device"], + "additionalProperties": False + }, + "UNIX": { + "description": "UNIX Network Input/Output", + "properties": { + "type": { + "enum": ["nio_unix"] + }, + "local_file": { + "description": "path to the UNIX socket file (local)", + "type": "string", + "minLength": 1 + }, + "remote_file": { + "description": "path to the UNIX socket file (remote)", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "local_file", "remote_file"], + "additionalProperties": False + }, + "VDE": { + "description": "VDE Network Input/Output", + "properties": { + "type": { + "enum": ["nio_vde"] + }, + "control_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + "local_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "control_file", "local_file"], + "additionalProperties": False + }, + "NULL": { + "description": "NULL Network Input/Output", + "properties": { + "type": { + "enum": ["nio_null"] + }, + }, + "required": ["type"], + "additionalProperties": False + }, + }, + + "properties": { + "id": { + "description": "Frame relay switch instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the Frame relay switch instance", + "type": "integer" + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 1, + }, + "mappings": { + "type": "object", + }, + "nio": { + "type": "object", + "description": "Network Input/Output", + "oneOf": [ + {"$ref": "#/definitions/UDP"}, + {"$ref": "#/definitions/Ethernet"}, + {"$ref": "#/definitions/LinuxEthernet"}, + {"$ref": "#/definitions/TAP"}, + {"$ref": "#/definitions/UNIX"}, + {"$ref": "#/definitions/VDE"}, + {"$ref": "#/definitions/NULL"}, + ] + }, + }, + "required": ["id", "port", "port_id", "mappings", "nio"], +} + +FRSW_DELETE_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete a NIO for a Frame relay switch instance", + "type": "object", + "properties": { + "id": { + "description": "Frame relay switch instance ID", + "type": "integer" + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 1, + }, + }, + "required": ["id", "port"] +} diff --git a/gns3server/modules/dynamips/schemas/vm.py b/gns3server/modules/dynamips/schemas/vm.py new file mode 100644 index 00000000..3180d371 --- /dev/null +++ b/gns3server/modules/dynamips/schemas/vm.py @@ -0,0 +1,541 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2014 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +VM_CREATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to create a new VM instance", + "type": "object", + "properties": { + "name": { + "description": "Router name", + "type": "string", + "minLength": 1, + }, + "platform": { + "description": "router platform", + "type": "string", + "minLength": 1, + "pattern": "^c[0-9]{4}$" + }, + "chassis": { + "description": "router chassis model", + "type": "string", + "minLength": 1, + "pattern": "^[0-9]{4}$" + }, + "image": { + "description": "path to the IOS image file", + "type": "string", + "minLength": 1 + }, + "ram": { + "description": "amount of RAM in MB", + "type": "integer" + }, + "console": { + "description": "console TCP port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "aux": { + "description": "auxiliary console TCP port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "mac_address": { + "description": "base MAC address", + "type": "string", + "minLength": 1, + "pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$" + } + }, + "required": ["platform", "image", "ram"] +} + +VM_DELETE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete a VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +VM_START_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to start a VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +VM_STOP_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to stop a VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +VM_SUSPEND_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to suspend a VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +VM_RELOAD_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to reload a VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +#TODO: platform specific properties? +VM_UPDATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to update a VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + "name": { + "description": "Router name", + "type": "string", + "minLength": 1, + }, + "platform": { + "description": "platform", + "type": "string", + "minLength": 1, + "pattern": "^c[0-9]{4}$" + }, + "image": { + "description": "path to the IOS image", + "type": "string", + "minLength": 1, + }, + "startup_config": { + "description": "path to the IOS startup configuration file", + "type": "string", + "minLength": 1, + }, + "private_config": { + "description": "path to the IOS private configuration file", + "type": "string", + "minLength": 1, + }, + "ram": { + "description": "amount of RAM in MB", + "type": "integer" + }, + "nvram": { + "description": "amount of NVRAM in KB", + "type": "integer" + }, + "mmap": { + "description": "MMAP feature", + "type": "boolean" + }, + "sparsemem": { + "description": "sparse memory feature", + "type": "boolean" + }, + "clock_divisor": { + "description": "clock divisor", + "type": "integer" + }, + "idlepc": { + "description": "idle-pc value", + "type": "string", + "minLength": 1, + "pattern": "^0x[0-9a-fA-F]+$" + }, + "idlemax": { + "description": "idlemax value", + "type": "integer", + }, + "idlesleep": { + "description": "idlesleep value", + "type": "integer", + }, + "exec_area": { + "description": "exec area value", + "type": "integer", + }, + "jit_sharing_group": { + "description": "JIT sharing group", + "type": "integer", + }, + "disk0": { + "description": "disk0 size in MB", + "type": "integer" + }, + "disk1": { + "description": "disk1 size in MB", + "type": "integer" + }, + "confreg": { + "description": "configuration register", + "type": "string", + "minLength": 1, + "pattern": "^0x[0-9a-fA-F]{4}$" + }, + "console": { + "description": "console TCP port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "aux": { + "description": "auxiliary console TCP port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "mac_address": { + "description": "base MAC address", + "type": "string", + "minLength": 1, + "pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$" + }, + "system_id": { + "description": "system ID", + "type": "string", + "minLength": 1, + }, + "slot0": { + "description": "Network module slot 0", + "type": "string", + }, + "slot1": { + "description": "Network module slot 1", + "type": "string", + }, + "slot2": { + "description": "Network module slot 2", + "type": "string", + }, + "slot3": { + "description": "Network module slot 3", + "type": "string", + }, + "slot4": { + "description": "Network module slot 4", + "type": "string", + }, + "slot5": { + "description": "Network module slot 5", + "type": "string", + }, + "slot6": { + "description": "Network module slot 6", + "type": "string", + }, + "wic0": { + "description": "Network module WIC slot 0", + "type": "string", + }, + "wic1": { + "description": "Network module WIC slot 0", + "type": "string", + }, + "wic2": { + "description": "Network module WIC slot 0", + "type": "string", + }, + "startup_config_base64": { + "description": "startup configuration base64 encoded", + "type": "string" + }, + "private_config_base64": { + "description": "private configuration base64 encoded", + "type": "string" + }, + }, + "required": ["id"] +} + +VM_SAVE_CONFIG_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to save the configs for VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + }, + "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", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + "compute": { + "description": "indicates to compute new idle-pc values", + "type": "boolean" + }, + }, + "required": ["id"] +} + +VM_ALLOCATE_UDP_PORT_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to allocate an UDP port for a VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the VM instance", + "type": "integer" + }, + }, + "required": ["id", "port_id"] +} + +VM_ADD_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to add a NIO for a VM instance", + "type": "object", + + "definitions": { + "UDP": { + "description": "UDP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_udp"] + }, + "lport": { + "description": "Local port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "rhost": { + "description": "Remote host", + "type": "string", + "minLength": 1 + }, + "rport": { + "description": "Remote port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + } + }, + "required": ["type", "lport", "rhost", "rport"], + "additionalProperties": False + }, + "Ethernet": { + "description": "Generic Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_generic_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "LinuxEthernet": { + "description": "Linux Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_linux_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "TAP": { + "description": "TAP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_tap"] + }, + "tap_device": { + "description": "TAP device name e.g. tap0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "tap_device"], + "additionalProperties": False + }, + "UNIX": { + "description": "UNIX Network Input/Output", + "properties": { + "type": { + "enum": ["nio_unix"] + }, + "local_file": { + "description": "path to the UNIX socket file (local)", + "type": "string", + "minLength": 1 + }, + "remote_file": { + "description": "path to the UNIX socket file (remote)", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "local_file", "remote_file"], + "additionalProperties": False + }, + "VDE": { + "description": "VDE Network Input/Output", + "properties": { + "type": { + "enum": ["nio_vde"] + }, + "control_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + "local_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "control_file", "local_file"], + "additionalProperties": False + }, + "NULL": { + "description": "NULL Network Input/Output", + "properties": { + "type": { + "enum": ["nio_null"] + }, + }, + "required": ["type"], + "additionalProperties": False + }, + }, + + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the VM instance", + "type": "integer" + }, + "slot": { + "description": "Slot number", + "type": "integer", + "minimum": 0, + "maximum": 6 + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 0, + "maximum": 15 + }, + "nio": { + "type": "object", + "description": "Network Input/Output", + "oneOf": [ + {"$ref": "#/definitions/UDP"}, + {"$ref": "#/definitions/Ethernet"}, + {"$ref": "#/definitions/LinuxEthernet"}, + {"$ref": "#/definitions/TAP"}, + {"$ref": "#/definitions/UNIX"}, + {"$ref": "#/definitions/VDE"}, + {"$ref": "#/definitions/NULL"}, + ] + }, + }, + "required": ["id", "port_id", "slot", "port", "nio"] +} + +VM_DELETE_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete a NIO for a VM instance", + "type": "object", + "properties": { + "id": { + "description": "VM instance ID", + "type": "integer" + }, + "slot": { + "description": "Slot number", + "type": "integer", + "minimum": 0, + "maximum": 6 + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 0, + "maximum": 15 + }, + }, + "required": ["id", "slot", "port"] +} diff --git a/gns3server/modules/iou/__init__.py b/gns3server/modules/iou/__init__.py index 67c6518d..5e896e08 100644 --- a/gns3server/modules/iou/__init__.py +++ b/gns3server/modules/iou/__init__.py @@ -27,6 +27,7 @@ import fcntl import struct import socket import shutil + from gns3server.modules import IModule from gns3server.config import Config from .iou_device import IOUDevice @@ -36,6 +37,16 @@ from .nios.nio_tap import NIO_TAP from .nios.nio_generic_ethernet import NIO_GenericEthernet import gns3server.jsonrpc as jsonrpc +from .schemas import IOU_CREATE_SCHEMA +from .schemas import IOU_DELETE_SCHEMA +from .schemas import IOU_UPDATE_SCHEMA +from .schemas import IOU_START_SCHEMA +from .schemas import IOU_STOP_SCHEMA +from .schemas import IOU_RELOAD_SCHEMA +from .schemas import IOU_ALLOCATE_UDP_PORT_SCHEMA +from .schemas import IOU_ADD_NIO_SCHEMA +from .schemas import IOU_DELETE_NIO_SCHEMA + import logging log = logging.getLogger(__name__) @@ -132,6 +143,21 @@ class IOU(IModule): self.send_notification("{}.iouyap_stopped".format(self.name), notification) iou_instance.stop() + def get_iou_instance(self, iou_id): + """ + Returns an IOU device instance. + + :param iou_id: IOU device identifier + + :returns: IOUDevice instance + """ + + if iou_id not in self._iou_instances: + log.debug("IOU device ID {} doesn't exist".format(iou_id), exc_info=1) + self.send_custom_error("IOU device ID {} doesn't exist".format(iou_id)) + return None + return self._iou_instances[iou_id] + @IModule.route("iou.reset") def reset(self, request): """ @@ -238,22 +264,27 @@ class IOU(IModule): """ Creates a new IOU instance. + Mandatory request parameters: + - path (path to the IOU executable) + Optional request parameters: - name (IOU name) - - path (path to the IOU executable) Response parameters: - id (IOU instance identifier) - name (IOU name) + - default settings :param request: JSON request """ - #TODO: JSON schema validation for the request + # validate the request + if not self.validate_request(request, IOU_CREATE_SCHEMA): + return + name = None - if request and "name" in request: + if "name" in request: name = request["name"] - iou_path = request["path"] try: @@ -290,31 +321,29 @@ class IOU(IModule): Mandatory request parameters: - id (IOU instance identifier) - Response parameters: - - same as original request + Response parameter: + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, IOU_DELETE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - iou_id = request["id"] - if iou_id not in self._iou_instances: - self.send_custom_error("IOU device id {} doesn't exist".format(iou_id)) + # get the instance + iou_instance = self.get_iou_instance(request["id"]) + if not iou_instance: return - iou_instance = self._iou_instances[iou_id] try: iou_instance.delete() - del self._iou_instances[iou_id] + del self._iou_instances[request["id"]] except IOUError as e: self.send_custom_error(str(e)) return - self.send_response(request) + + self.send_response(True) @IModule.route("iou.update") def iou_update(self, request): @@ -329,23 +358,21 @@ class IOU(IModule): - startup_config_base64 (startup-config base64 encoded) Response parameters: - - same as original request + - updated settings :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, IOU_UPDATE_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - iou_id = request["id"] - if iou_id not in self._iou_instances: - self.send_custom_error("IOU device id {} doesn't exist".format(iou_id)) + # get the instance + iou_instance = self.get_iou_instance(request["id"]) + if not iou_instance: return - iou_instance = self._iou_instances[iou_id] + response = {} try: # a new startup-config has been pushed if "startup_config_base64" in request: @@ -359,9 +386,9 @@ class IOU(IModule): f.write(config) except OSError as e: raise IOUError("Could not save the configuration {}: {}".format(config_path, e)) - request["startup_config"] = os.path.basename(config_path) + response["startup_config"] = os.path.basename(config_path) if "startup_config" in request: - iou_instance.startup_config = request["startup_config"] + iou_instance.startup_config = response["startup_config"] except IOUError as e: self.send_custom_error(str(e)) return @@ -370,11 +397,12 @@ class IOU(IModule): if hasattr(iou_instance, name) and getattr(iou_instance, name) != value: try: setattr(iou_instance, name, value) + response[name] = value except IOUError as e: self.send_custom_error(str(e)) return - self.send_response(request) + self.send_response(response) @IModule.route("iou.start") def vm_start(self, request): @@ -385,22 +413,19 @@ class IOU(IModule): - id (IOU instance identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, IOU_START_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - iou_id = request["id"] - if iou_id not in self._iou_instances: - self.send_custom_error("IOU device id {} doesn't exist".format(iou_id)) + # get the instance + iou_instance = self.get_iou_instance(request["id"]) + if not iou_instance: return - iou_instance = self._iou_instances[iou_id] try: log.debug("starting IOU with command: {}".format(iou_instance.command())) @@ -410,7 +435,7 @@ class IOU(IModule): except IOUError as e: self.send_custom_error(str(e)) return - self.send_response(request) + self.send_response(True) @IModule.route("iou.stop") def vm_stop(self, request): @@ -421,29 +446,26 @@ class IOU(IModule): - id (IOU instance identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, IOU_STOP_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - iou_id = request["id"] - if iou_id not in self._iou_instances: - self.send_custom_error("IOU device id {} doesn't exist".format(iou_id)) + # get the instance + iou_instance = self.get_iou_instance(request["id"]) + if not iou_instance: return - iou_instance = self._iou_instances[iou_id] try: iou_instance.stop() except IOUError as e: self.send_custom_error(str(e)) return - self.send_response(request) + self.send_response(True) @IModule.route("iou.reload") def vm_reload(self, request): @@ -454,22 +476,19 @@ class IOU(IModule): - id (IOU identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, IOU_RELOAD_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - iou_id = request["id"] - if iou_id not in self._iou_instances: - self.send_custom_error("IOU device id {} doesn't exist".format(iou_id)) + # get the instance + iou_instance = self.get_iou_instance(request["id"]) + if not iou_instance: return - iou_instance = self._iou_instances[iou_id] try: if iou_instance.is_running(): @@ -478,7 +497,7 @@ class IOU(IModule): except IOUError as e: self.send_custom_error(str(e)) return - self.send_response(request) + self.send_response(True) @IModule.route("iou.allocate_udp_port") def allocate_udp_port(self, request): @@ -496,17 +515,14 @@ class IOU(IModule): :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, IOU_ALLOCATE_UDP_PORT_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - iou_id = request["id"] - if iou_id not in self._iou_instances: - self.send_custom_error("IOU device id {} doesn't exist".format(iou_id)) + # get the instance + iou_instance = self.get_iou_instance(request["id"]) + if not iou_instance: return - iou_instance = self._iou_instances[iou_id] try: @@ -516,8 +532,8 @@ class IOU(IModule): port = IOUDevice.find_unused_port(self._current_udp_port, self._udp_end_port_range, host=self._host, socket_type="UDP") self._current_udp_port += 1 - log.info("{} [id={}] has allocated UDP port {} with host {}".format(iou_instance .name, - iou_instance .id, + log.info("{} [id={}] has allocated UDP port {} with host {}".format(iou_instance.name, + iou_instance.id, port, self._host)) response = {"lport": port} @@ -539,75 +555,48 @@ class IOU(IModule): - slot (slot number) - port (port number) - port_id (unique port identifier) - - nio (nio type, one of the following) - - "NIO_UDP" + - nio (one of the following) + - type "nio_udp" - lport (local port) - rhost (remote host) - rport (remote port) - - "NIO_GenericEthernet" + - type "nio_generic_ethernet" - ethernet_device (Ethernet device name e.g. eth0) - - "NIO_TAP" + - type "nio_tap" - tap_device (TAP device name e.g. tap0) Response parameters: - - same as original request + - port_id (unique port identifier) :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, IOU_ADD_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - iou_id = request["id"] - if iou_id not in self._iou_instances: - self.send_custom_error("IOU device id {} doesn't exist".format(iou_id)) + # get the instance + iou_instance = self.get_iou_instance(request["id"]) + if not iou_instance: return - iou_instance = self._iou_instances[iou_id] slot = request["slot"] port = request["port"] - try: nio = None - if request["nio"] == "NIO_UDP": - lport = request["lport"] - rhost = request["rhost"] - rport = request["rport"] + if request["nio"]["type"] == "nio_udp": + lport = request["nio"]["lport"] + rhost = request["nio"]["rhost"] + rport = request["nio"]["rport"] nio = NIO_UDP(lport, rhost, rport) - elif request["nio"] == "NIO_TAP": - tap_device = request["tap_device"] - -# # check that we have access to the tap device -# TUNSETIFF = 0x400454ca -# IFF_TAP = 0x0002 -# IFF_NO_PI = 0x1000 -# try: -# tun = os.open("/dev/net/tun", os.O_RDWR) -# except OSError as e: -# raise IOUError("Could not open /dev/net/tun: {}".format(e)) -# ifr = struct.pack("16sH", tap_device.encode("utf-8"), IFF_TAP | IFF_NO_PI) -# try: -# fcntl.ioctl(tun, TUNSETIFF, ifr) -# os.close(tun) -# except IOError as e: -# raise IOUError("TAP NIO {}: {}".format(tap_device, e)) - + elif request["nio"]["type"] == "nio_tap": + tap_device = request["nio"]["tap_device"] nio = NIO_TAP(tap_device) - elif request["nio"] == "NIO_GenericEthernet": - ethernet_device = request["ethernet_device"] - -# # check that we have access to the Ethernet device -# try: -# with socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW): -# pass -# except socket.error as e: -# raise IOUError("Generic Ethernet NIO {}: {}".format(ethernet_device, e)) + elif request["nio"]["type"] == "nio_generic_ethernet": + ethernet_device = request["nio"]["ethernet_device"] nio = NIO_GenericEthernet(ethernet_device) if not nio: - raise IOUError("Requested NIO doesn't exist or is not supported: {}".format(request["nio"])) + raise IOUError("Requested NIO does not exist or is not supported: {}".format(request["nio"]["type"])) except IOUError as e: self.send_custom_error(str(e)) return @@ -618,8 +607,7 @@ class IOU(IModule): self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response({"port_id": request["port_id"]}) @IModule.route("iou.delete_nio") def delete_nio(self, request): @@ -632,33 +620,29 @@ class IOU(IModule): - port (port identifier) Response parameters: - - same as original request + - True on success :param request: JSON request """ - if request == None: - self.send_param_error() + # validate the request + if not self.validate_request(request, IOU_DELETE_NIO_SCHEMA): return - #TODO: JSON schema validation for the request - log.debug("received request {}".format(request)) - iou_id = request["id"] - iou_instance = self._iou_instances[iou_id] - if iou_id not in self._iou_instances: - self.send_custom_error("IOU device id {} doesn't exist".format(iou_id)) + # get the instance + iou_instance = self.get_iou_instance(request["id"]) + if not iou_instance: return + slot = request["slot"] port = request["port"] - try: iou_instance.slot_remove_nio_binding(slot, port) except IOUError as e: self.send_custom_error(str(e)) return - # for now send back the original request - self.send_response(request) + self.send_response(True) @IModule.route("iou.echo") def echo(self, request): diff --git a/gns3server/modules/iou/ioucon.py b/gns3server/modules/iou/ioucon.py index e767b73d..138b61e7 100644 --- a/gns3server/modules/iou/ioucon.py +++ b/gns3server/modules/iou/ioucon.py @@ -402,8 +402,7 @@ class IOU(Router): try: self.fd.connect(self.ttyS) except FileNotFoundError: - log.debug("Waiting to connect to {}".format(self.ttyS), - file=sys.stderr) + log.debug("Waiting to connect to {}".format(self.ttyS)) time.sleep(RETRY_DELAY) except Exception as e: raise NetioError("Couldn't connect to socket {}: {}" diff --git a/gns3server/modules/iou/schemas.py b/gns3server/modules/iou/schemas.py new file mode 100644 index 00000000..62ac0ec4 --- /dev/null +++ b/gns3server/modules/iou/schemas.py @@ -0,0 +1,364 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2014 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +IOU_CREATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to create a new IOU instance", + "type": "object", + "properties": { + "name": { + "description": "IOU device name", + "type": "string", + "minLength": 1, + }, + "path": { + "description": "path to the IOU executable", + "type": "string", + "minLength": 1, + } + }, + "required": ["path"] +} + +IOU_DELETE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete an IOU instance", + "type": "object", + "properties": { + "id": { + "description": "IOU device instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +IOU_UPDATE_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to update an IOU instance", + "type": "object", + "properties": { + "id": { + "description": "IOU device instance ID", + "type": "integer" + }, + "name": { + "description": "IOU device name", + "type": "string", + "minLength": 1, + }, + "path": { + "description": "path to the IOU executable", + "type": "string", + "minLength": 1, + }, + "startup_config": { + "description": "path to the IOU startup configuration file", + "type": "string", + "minLength": 1, + }, + "ram": { + "description": "amount of RAM in MB", + "type": "integer" + }, + "nvram": { + "description": "amount of NVRAM in KB", + "type": "integer" + }, + "ethernet_adapters": { + "description": "number of Ethernet adapters", + "type": "integer", + "minimum": 0, + "maximum": 16, + }, + "serial_adapters": { + "description": "number of serial adapters", + "type": "integer", + "minimum": 0, + "maximum": 16, + }, + "console": { + "description": "console TCP port", + "minimum": 1, + "maximum": 65535, + "type": "integer" + }, + "startup_config_base64": { + "description": "startup configuration base64 encoded", + "type": "string" + }, + }, + "required": ["id"] +} + +IOU_START_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to start an IOU instance", + "type": "object", + "properties": { + "id": { + "description": "IOU device instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +IOU_STOP_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to stop an IOU instance", + "type": "object", + "properties": { + "id": { + "description": "IOU device instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +IOU_RELOAD_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to reload an IOU instance", + "type": "object", + "properties": { + "id": { + "description": "IOU device instance ID", + "type": "integer" + }, + }, + "required": ["id"] +} + +IOU_ALLOCATE_UDP_PORT_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to allocate an UDP port for an IOU instance", + "type": "object", + "properties": { + "id": { + "description": "IOU device instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the IOU instance", + "type": "integer" + }, + }, + "required": ["id", "port_id"] +} + +IOU_ADD_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to add a NIO for an IOU instance", + "type": "object", + + "definitions": { + "UDP": { + "description": "UDP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_udp"] + }, + "lport": { + "description": "Local port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "rhost": { + "description": "Remote host", + "type": "string", + "minLength": 1 + }, + "rport": { + "description": "Remote port", + "type": "integer", + "minimum": 1, + "maximum": 65535 + } + }, + "required": ["type", "lport", "rhost", "rport"], + "additionalProperties": False + }, + "Ethernet": { + "description": "Generic Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_generic_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "LinuxEthernet": { + "description": "Linux Ethernet Network Input/Output", + "properties": { + "type": { + "enum": ["nio_linux_ethernet"] + }, + "ethernet_device": { + "description": "Ethernet device name e.g. eth0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "ethernet_device"], + "additionalProperties": False + }, + "TAP": { + "description": "TAP Network Input/Output", + "properties": { + "type": { + "enum": ["nio_tap"] + }, + "tap_device": { + "description": "TAP device name e.g. tap0", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "tap_device"], + "additionalProperties": False + }, + "UNIX": { + "description": "UNIX Network Input/Output", + "properties": { + "type": { + "enum": ["nio_unix"] + }, + "local_file": { + "description": "path to the UNIX socket file (local)", + "type": "string", + "minLength": 1 + }, + "remote_file": { + "description": "path to the UNIX socket file (remote)", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "local_file", "remote_file"], + "additionalProperties": False + }, + "VDE": { + "description": "VDE Network Input/Output", + "properties": { + "type": { + "enum": ["nio_vde"] + }, + "control_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + "local_file": { + "description": "path to the VDE control file", + "type": "string", + "minLength": 1 + }, + }, + "required": ["type", "control_file", "local_file"], + "additionalProperties": False + }, + "NULL": { + "description": "NULL Network Input/Output", + "properties": { + "type": { + "enum": ["nio_null"] + }, + }, + "required": ["type"], + "additionalProperties": False + }, + }, + + "properties": { + "id": { + "description": "IOU device instance ID", + "type": "integer" + }, + "port_id": { + "description": "Unique port identifier for the IOU instance", + "type": "integer" + }, + "slot": { + "description": "Slot number", + "type": "integer", + "minimum": 0, + "maximum": 15 + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 0, + "maximum": 3 + }, + + "slot": { + "description": "Slot number", + "type": "integer", + "minimum": 0, + "maximum": 15 + }, + "nio": { + "type": "object", + "description": "Network Input/Output", + "oneOf": [ + {"$ref": "#/definitions/UDP"}, + {"$ref": "#/definitions/Ethernet"}, + {"$ref": "#/definitions/LinuxEthernet"}, + {"$ref": "#/definitions/TAP"}, + {"$ref": "#/definitions/UNIX"}, + {"$ref": "#/definitions/VDE"}, + {"$ref": "#/definitions/NULL"}, + ] + }, + }, + "required": ["id", "port_id", "slot", "port", "nio"] +} + + +IOU_DELETE_NIO_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request validation to delete a NIO for an IOU instance", + "type": "object", + "properties": { + "id": { + "description": "IOU device instance ID", + "type": "integer" + }, + "slot": { + "description": "Slot number", + "type": "integer", + "minimum": 0, + "maximum": 15 + }, + "port": { + "description": "Port number", + "type": "integer", + "minimum": 0, + "maximum": 3 + }, + }, + "required": ["id", "slot", "port"] +} diff --git a/gns3server/version.py b/gns3server/version.py index df08e796..51280f0e 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,5 +23,5 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "1.0a3.dev1" +__version__ = "1.0a3.dev2" __version_info__ = (1, 0, 0, -99) diff --git a/requirements.txt b/requirements.txt index e7638d60..6fb17eea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ tornado pyzmq netifaces-py3 +jsonschema diff --git a/setup.py b/setup.py index 18e3c432..4e4b9e41 100644 --- a/setup.py +++ b/setup.py @@ -47,6 +47,7 @@ setup( install_requires=[ "tornado >= 3.1", "pyzmq", + "jsonschema" ], entry_points={ "console_scripts": [