diff --git a/gns3server/compute/dynamips/dynamips_device_factory.py b/gns3server/compute/dynamips/dynamips_device_factory.py index da44a55d..bae2db84 100644 --- a/gns3server/compute/dynamips/dynamips_device_factory.py +++ b/gns3server/compute/dynamips/dynamips_device_factory.py @@ -37,9 +37,9 @@ class DynamipsDeviceFactory: Factory to create an Device object based on the type """ - def __new__(cls, name, device_id, project, manager, device_type, **kwargs): + def __new__(cls, name, node_id, project, manager, device_type, **kwargs): if device_type not in DEVICES: raise DynamipsError("Unknown device type: {}".format(device_type)) - return DEVICES[device_type](name, device_id, project, manager, **kwargs) + return DEVICES[device_type](name, node_id, project, manager, **kwargs) diff --git a/gns3server/compute/dynamips/nodes/atm_switch.py b/gns3server/compute/dynamips/nodes/atm_switch.py index 86dc2305..fc0e3330 100644 --- a/gns3server/compute/dynamips/nodes/atm_switch.py +++ b/gns3server/compute/dynamips/nodes/atm_switch.py @@ -37,28 +37,32 @@ class ATMSwitch(Device): Dynamips ATM switch. :param name: name for this switch - :param device_id: Device instance identifier + :param node_id: Node instance identifier :param project: Project instance :param manager: Parent VM Manager :param hypervisor: Dynamips hypervisor instance """ - def __init__(self, name, device_id, project, manager, hypervisor=None): + def __init__(self, name, node_id, project, manager, mappings=None, hypervisor=None): - super().__init__(name, device_id, project, manager, hypervisor) + super().__init__(name, node_id, project, manager, hypervisor) self._nios = {} + self._active_mappings = {} self._mappings = {} + if mappings: + self._mappings = mappings def __json__(self): mappings = {} for source, destination in self._mappings.items(): - mappings[str(source)] = str(destination) + mappings[source] = destination return {"name": self.name, - "device_id": self.id, + "node_id": self.id, "project_id": self.project.id, - "mappings": mappings} + "mappings": mappings, + "status": "started"} @asyncio.coroutine def create(self): @@ -105,6 +109,16 @@ class ATMSwitch(Device): return self._mappings + @mappings.setter + def mappings(self, mappings): + """ + Sets port mappings + + :param mappings: mappings list + """ + + self._mappings = mappings + @asyncio.coroutine def delete(self): """ @@ -136,6 +150,7 @@ class ATMSwitch(Device): return True return False + @asyncio.coroutine def add_nio(self, nio, port_number): """ Adds a NIO as new port on ATM switch. @@ -153,6 +168,7 @@ class ATMSwitch(Device): port=port_number)) self._nios[port_number] = nio + yield from self.set_mappings(self._mappings) @asyncio.coroutine def remove_nio(self, port_number): @@ -166,18 +182,21 @@ class ATMSwitch(Device): raise DynamipsError("Port {} is not allocated".format(port_number)) # remove VCs mapped with the port - for source, destination in self._mappings.copy().items(): - if len(source) == 3 and len(destination) == 3: + pvc_entry = re.compile(r"""^([0-9]*):([0-9]*):([0-9]*)$""") + for source, destination in self._active_mappings.copy().items(): + match_source_pvc = pvc_entry.search(source) + match_destination_pvc = pvc_entry.search(destination) + if match_source_pvc and match_destination_pvc: # remove the virtual channels mapped with this port/nio - source_port, source_vpi, source_vci = source - destination_port, destination_vpi, destination_vci = destination + source_port, source_vpi, source_vci = map(int, match_source_pvc.group(1, 2, 3)) + destination_port, destination_vpi, destination_vci = map(int, match_destination_pvc.group(1, 2, 3)) if port_number == source_port: yield from self.unmap_pvc(source_port, source_vpi, source_vci, destination_port, destination_vpi, destination_vci) yield from self.unmap_pvc(destination_port, destination_vpi, destination_vci, source_port, source_vpi, source_vci) else: # remove the virtual paths mapped with this port/nio - source_port, source_vpi = source - destination_port, destination_vpi = destination + source_port, source_vpi = map(int, source.split(':')) + destination_port, destination_vpi = map(int, destination.split(':')) if port_number == source_port: yield from self.unmap_vp(source_port, source_vpi, destination_port, destination_vpi) yield from self.unmap_vp(destination_port, destination_vpi, source_port, source_vpi) @@ -212,8 +231,8 @@ class ATMSwitch(Device): source_port, source_vpi, source_vci = map(int, match_source_pvc.group(1, 2, 3)) destination_port, destination_vpi, destination_vci = map(int, match_destination_pvc.group(1, 2, 3)) if self.has_port(destination_port): - if (source_port, source_vpi, source_vci) not in self.mappings and \ - (destination_port, destination_vpi, destination_vci) not in self.mappings: + if (source_port, source_vpi, source_vci) not in self._active_mappings and \ + (destination_port, destination_vpi, destination_vci) not in self._active_mappings: yield from self.map_pvc(source_port, source_vpi, source_vci, destination_port, destination_vpi, destination_vci) yield from self.map_pvc(destination_port, destination_vpi, destination_vci, source_port, source_vpi, source_vci) else: @@ -221,7 +240,7 @@ class ATMSwitch(Device): source_port, source_vpi = map(int, source.split(':')) destination_port, destination_vpi = map(int, destination.split(':')) if self.has_port(destination_port): - if (source_port, source_vpi) not in self.mappings and (destination_port, destination_vpi) not in self.mappings: + if (source_port, source_vpi) not in self._active_mappings and (destination_port, destination_vpi) not in self._active_mappings: yield from self.map_vp(source_port, source_vpi, destination_port, destination_vpi) yield from self.map_vp(destination_port, destination_vpi, source_port, source_vpi) @@ -258,7 +277,7 @@ class ATMSwitch(Device): port2=port2, vpi2=vpi2)) - self._mappings[(port1, vpi1)] = (port2, vpi2) + self._active_mappings["{}:{}".format(port1, vpi1)] = "{}:{}".format(port2, vpi2) @asyncio.coroutine def unmap_vp(self, port1, vpi1, port2, vpi2): @@ -293,7 +312,7 @@ class ATMSwitch(Device): port2=port2, vpi2=vpi2)) - del self._mappings[(port1, vpi1)] + del self._active_mappings["{}:{}".format(port1, vpi1)] @asyncio.coroutine def map_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2): @@ -334,7 +353,7 @@ class ATMSwitch(Device): vpi2=vpi2, vci2=vci2)) - self._mappings[(port1, vpi1, vci1)] = (port2, vpi2, vci2) + self._active_mappings["{}:{}:{}".format(port1, vpi1, vci1)] = "{}:{}:{}".format(port2, vpi2, vci2) @asyncio.coroutine def unmap_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2): @@ -374,7 +393,7 @@ class ATMSwitch(Device): port2=port2, vpi2=vpi2, vci2=vci2)) - del self._mappings[(port1, vpi1, vci1)] + del self._active_mappings["{}:{}:{}".format(port1, vpi1, vci1)] @asyncio.coroutine def start_capture(self, port_number, output_file, data_link_type="DLT_ATM_RFC1483"): diff --git a/gns3server/compute/dynamips/nodes/device.py b/gns3server/compute/dynamips/nodes/device.py index 9b0577ee..3fcb26f7 100644 --- a/gns3server/compute/dynamips/nodes/device.py +++ b/gns3server/compute/dynamips/nodes/device.py @@ -22,7 +22,7 @@ class Device: Base device for switches and hubs :param name: name for this device - :param device_id: Device instance identifier + :param node_id: Node instance identifier :param project: Project instance :param manager: Parent manager :param hypervisor: Dynamips hypervisor instance diff --git a/gns3server/compute/dynamips/nodes/frame_relay_switch.py b/gns3server/compute/dynamips/nodes/frame_relay_switch.py index 9039dca6..3ec39001 100644 --- a/gns3server/compute/dynamips/nodes/frame_relay_switch.py +++ b/gns3server/compute/dynamips/nodes/frame_relay_switch.py @@ -36,28 +36,32 @@ class FrameRelaySwitch(Device): Dynamips Frame Relay switch. :param name: name for this switch - :param device_id: Device instance identifier + :param node_id: Node instance identifier :param project: Project instance :param manager: Parent VM Manager :param hypervisor: Dynamips hypervisor instance """ - def __init__(self, name, device_id, project, manager, hypervisor=None): + def __init__(self, name, node_id, project, manager, mappings=None, hypervisor=None): - super().__init__(name, device_id, project, manager, hypervisor) + super().__init__(name, node_id, project, manager, hypervisor) self._nios = {} + self._active_mappings = {} self._mappings = {} + if mappings: + self._mappings = mappings def __json__(self): mappings = {} for source, destination in self._mappings.items(): - mappings[str(source)] = str(destination) + mappings[source] = destination return {"name": self.name, - "device_id": self.id, + "node_id": self.id, "project_id": self.project.id, - "mappings": mappings} + "mappings": mappings, + "status": "started"} @asyncio.coroutine def create(self): @@ -104,6 +108,16 @@ class FrameRelaySwitch(Device): return self._mappings + @mappings.setter + def mappings(self, mappings): + """ + Sets port mappings + + :param mappings: mappings list + """ + + self._mappings = mappings + @asyncio.coroutine def delete(self): """ @@ -135,6 +149,7 @@ class FrameRelaySwitch(Device): return True return False + @asyncio.coroutine def add_nio(self, nio, port_number): """ Adds a NIO as new port on Frame Relay switch. @@ -152,6 +167,7 @@ class FrameRelaySwitch(Device): port=port_number)) self._nios[port_number] = nio + yield from self.set_mappings(self._mappings) @asyncio.coroutine def remove_nio(self, port_number): @@ -167,9 +183,9 @@ class FrameRelaySwitch(Device): raise DynamipsError("Port {} is not allocated".format(port_number)) # remove VCs mapped with the port - for source, destination in self._mappings.copy().items(): - source_port, source_dlci = source - destination_port, destination_dlci = destination + for source, destination in self._active_mappings.copy().items(): + source_port, source_dlci = map(int, source.split(':')) + destination_port, destination_dlci = map(int, destination.split(':')) if port_number == source_port: yield from self.unmap_vc(source_port, source_dlci, destination_port, destination_dlci) yield from self.unmap_vc(destination_port, destination_dlci, source_port, source_dlci) @@ -200,7 +216,7 @@ class FrameRelaySwitch(Device): source_port, source_dlci = map(int, source.split(':')) destination_port, destination_dlci = map(int, destination.split(':')) if self.has_port(destination_port): - if (source_port, source_dlci) not in self.mappings and (destination_port, destination_dlci) not in self.mappings: + if (source_port, source_dlci) not in self._active_mappings and (destination_port, destination_dlci) not in self._active_mappings: yield from self.map_vc(source_port, source_dlci, destination_port, destination_dlci) yield from self.map_vc(destination_port, destination_dlci, source_port, source_dlci) @@ -237,7 +253,7 @@ class FrameRelaySwitch(Device): port2=port2, dlci2=dlci2)) - self._mappings[(port1, dlci1)] = (port2, dlci2) + self._active_mappings["{}:{}".format(port1, dlci1)] = "{}:{}".format(port2, dlci2) @asyncio.coroutine def unmap_vc(self, port1, dlci1, port2, dlci2): @@ -271,7 +287,7 @@ class FrameRelaySwitch(Device): dlci1=dlci1, port2=port2, dlci2=dlci2)) - del self._mappings[(port1, dlci1)] + del self._active_mappings["{}:{}".format(port1, dlci1)] @asyncio.coroutine def start_capture(self, port_number, output_file, data_link_type="DLT_FRELAY"): diff --git a/gns3server/handlers/api/compute/__init__.py b/gns3server/handlers/api/compute/__init__.py index ca5c61f8..965805b8 100644 --- a/gns3server/handlers/api/compute/__init__.py +++ b/gns3server/handlers/api/compute/__init__.py @@ -20,7 +20,6 @@ import os from .network_handler import NetworkHandler from .project_handler import ProjectHandler -from .dynamips_device_handler import DynamipsDeviceHandler from .dynamips_vm_handler import DynamipsVMHandler from .qemu_handler import QEMUHandler from .virtualbox_handler import VirtualBoxHandler @@ -31,6 +30,8 @@ from .version_handler import VersionHandler from .notification_handler import NotificationHandler from .ethernet_hub_handler import EthernetHubHandler from .ethernet_switch_handler import EthernetSwitchHandler +from .frame_relay_switch_handler import FrameRelaySwitchHandler +from .atm_switch_handler import ATMSwitchHandler if sys.platform.startswith("linux") or hasattr(sys, "_called_from_test") or os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1": # IOU runs only on Linux but test suite works on UNIX platform diff --git a/gns3server/handlers/api/compute/atm_switch_handler.py b/gns3server/handlers/api/compute/atm_switch_handler.py new file mode 100644 index 00000000..5a77628b --- /dev/null +++ b/gns3server/handlers/api/compute/atm_switch_handler.py @@ -0,0 +1,270 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2015 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 . + +import os + +from gns3server.web.route import Route +from gns3server.schemas.node import NODE_CAPTURE_SCHEMA +from gns3server.schemas.nio import NIO_SCHEMA +from gns3server.compute.dynamips import Dynamips + +from gns3server.schemas.atm_switch import ( + ATM_SWITCH_CREATE_SCHEMA, + ATM_SWITCH_OBJECT_SCHEMA, + ATM_SWITCH_UPDATE_SCHEMA +) + + +class ATMSwitchHandler: + + """ + API entry points for ATM switch. + """ + + @Route.post( + r"/projects/{project_id}/atm_switch/nodes", + parameters={ + "project_id": "Project UUID" + }, + status_codes={ + 201: "Instance created", + 400: "Invalid request", + 409: "Conflict" + }, + description="Create a new ATM switch instance", + input=ATM_SWITCH_CREATE_SCHEMA, + output=ATM_SWITCH_OBJECT_SCHEMA) + def create(request, response): + + # Use the Dynamips ATM switch to simulate this node + dynamips_manager = Dynamips.instance() + node = yield from dynamips_manager.create_device(request.json.pop("name"), + request.match_info["project_id"], + request.json.get("node_id"), + device_type="atm_switch", + mappings=request.json.get("mappings")) + response.set_status(201) + response.json(node) + + @Route.get( + r"/projects/{project_id}/atm_switch/nodes/{node_id}", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 200: "Success", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Get an ATM switch instance", + output=ATM_SWITCH_OBJECT_SCHEMA) + def show(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.json(node) + + @Route.put( + r"/projects/{project_id}/atm_switch/nodes/{node_id}", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 200: "Instance updated", + 400: "Invalid request", + 404: "Instance doesn't exist", + 409: "Conflict" + }, + description="Update an ATM switch instance", + input=ATM_SWITCH_UPDATE_SCHEMA, + output=ATM_SWITCH_OBJECT_SCHEMA) + def update(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + if "name" in request.json and node.name != request.json["name"]: + yield from node.set_name(request.json["name"]) + if "mappings" in request.json: + node.mappings = request.json["mappings"] + node.updated() + response.json(node) + + @Route.delete( + r"/projects/{project_id}/atm_switch/nodes/{node_id}", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance deleted", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Delete an ATM switch instance") + def delete(request, response): + + dynamips_manager = Dynamips.instance() + yield from dynamips_manager.delete_device(request.match_info["node_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/atm_switch/nodes/{node_id}/start", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance started", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Start an ATM switch") + def start(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/atm_switch/nodes/{node_id}/stop", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance stopped", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Stop an ATM switch") + def stop(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/atm_switch/nodes/{node_id}/suspend", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance suspended", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Suspend an ATM Relay switch") + def suspend(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/atm_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID", + "adapter_number": "Adapter on the switch (always 0)", + "port_number": "Port on the switch" + }, + status_codes={ + 201: "NIO created", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Add a NIO to an ATM switch instance", + input=NIO_SCHEMA, + output=NIO_SCHEMA) + def create_nio(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + nio = yield from dynamips_manager.create_nio(node, request.json) + port_number = int(request.match_info["port_number"]) + yield from node.add_nio(nio, port_number) + response.set_status(201) + response.json(nio) + + @Route.delete( + r"/projects/{project_id}/atm_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID", + "adapter_number": "Adapter on the switch (always 0)", + "port_number": "Port on the switch" + }, + status_codes={ + 204: "NIO deleted", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Remove a NIO from an ATM switch instance") + def delete_nio(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + port_number = int(request.match_info["port_number"]) + nio = yield from node.remove_nio(port_number) + yield from nio.delete() + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/atm_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID", + "adapter_number": "Adapter on the switch (always 0)", + "port_number": "Port on the switch" + }, + status_codes={ + 200: "Capture started", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Start a packet capture on an ATM switch instance", + input=NODE_CAPTURE_SCHEMA) + def start_capture(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + port_number = int(request.match_info["port_number"]) + pcap_file_path = os.path.join(node.project.capture_working_directory(), request.json["capture_file_name"]) + yield from node.start_capture(port_number, pcap_file_path, request.json["data_link_type"]) + response.json({"pcap_file_path": pcap_file_path}) + + @Route.post( + r"/projects/{project_id}/atm_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID", + "adapter_number": "Adapter on the switch (always 0)", + "port_number": "Port on the switch" + }, + status_codes={ + 204: "Capture stopped", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Stop a packet capture on an ATM switch instance") + def stop_capture(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + port_number = int(request.match_info["port_number"]) + yield from node.stop_capture(port_number) + response.set_status(204) diff --git a/gns3server/handlers/api/compute/dynamips_device_handler.py b/gns3server/handlers/api/compute/dynamips_device_handler.py deleted file mode 100644 index dd779317..00000000 --- a/gns3server/handlers/api/compute/dynamips_device_handler.py +++ /dev/null @@ -1,230 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2015 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 . - -import os -import asyncio - -from gns3server.web.route import Route -from gns3server.schemas.node import NODE_CAPTURE_SCHEMA -from gns3server.compute.dynamips import Dynamips - -from gns3server.schemas.dynamips_device import ( - DEVICE_CREATE_SCHEMA, - DEVICE_UPDATE_SCHEMA, - DEVICE_OBJECT_SCHEMA, - DEVICE_NIO_SCHEMA -) - - -class DynamipsDeviceHandler: - - """ - API entry points for Dynamips devices. - """ - - @Route.post( - r"/projects/{project_id}/dynamips/devices", - parameters={ - "project_id": "Project UUID" - }, - status_codes={ - 201: "Instance created", - 400: "Invalid request", - 409: "Conflict" - }, - description="Create a new Dynamips device instance", - input=DEVICE_CREATE_SCHEMA, - output=DEVICE_OBJECT_SCHEMA) - def create(request, response): - - dynamips_manager = Dynamips.instance() - device = yield from dynamips_manager.create_device(request.json.pop("name"), - request.match_info["project_id"], - request.json.get("device_id"), - request.json.get("device_type")) - - response.set_status(201) - response.json(device) - - @Route.get( - r"/projects/{project_id}/dynamips/devices/{device_id}", - parameters={ - "project_id": "Project UUID", - "device_id": "Device UUID" - }, - status_codes={ - 200: "Success", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Get a Dynamips device instance", - output=DEVICE_OBJECT_SCHEMA) - def show(request, response): - - dynamips_manager = Dynamips.instance() - device = dynamips_manager.get_device(request.match_info["device_id"], project_id=request.match_info["project_id"]) - response.json(device) - - @Route.put( - r"/projects/{project_id}/dynamips/devices/{device_id}", - parameters={ - "project_id": "Project UUID", - "device_id": "Device UUID" - }, - status_codes={ - 200: "Instance updated", - 400: "Invalid request", - 404: "Instance doesn't exist", - 409: "Conflict" - }, - description="Update a Dynamips device instance", - input=DEVICE_UPDATE_SCHEMA, - output=DEVICE_OBJECT_SCHEMA) - def update(request, response): - - dynamips_manager = Dynamips.instance() - device = dynamips_manager.get_device(request.match_info["device_id"], project_id=request.match_info["project_id"]) - - if "name" in request.json: - yield from device.set_name(request.json["name"]) - - if "ports" in request.json: - for port in request.json["ports"]: - yield from device.set_port_settings(port["port"], port) - - device.updated() - response.json(device) - - @Route.delete( - r"/projects/{project_id}/dynamips/devices/{device_id}", - parameters={ - "project_id": "Project UUID", - "device_id": "Device UUID" - }, - status_codes={ - 204: "Instance deleted", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Delete a Dynamips device instance") - def delete(request, response): - - dynamips_manager = Dynamips.instance() - yield from dynamips_manager.delete_device(request.match_info["device_id"]) - response.set_status(204) - - @Route.post( - r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/nio", - parameters={ - "project_id": "Project UUID", - "device_id": "Device UUID", - "port_number": "Port on the device" - }, - status_codes={ - 201: "NIO created", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Add a NIO to a Dynamips device instance", - input=DEVICE_NIO_SCHEMA) - def create_nio(request, response): - - dynamips_manager = Dynamips.instance() - device = dynamips_manager.get_device(request.match_info["device_id"], project_id=request.match_info["project_id"]) - nio = yield from dynamips_manager.create_nio(device, request.json["nio"]) - port_number = int(request.match_info["port_number"]) - port_settings = request.json.get("port_settings") - mappings = request.json.get("mappings") - - if asyncio.iscoroutinefunction(device.add_nio): - yield from device.add_nio(nio, port_number) - else: - device.add_nio(nio, port_number) - - if port_settings: - yield from device.set_port_settings(port_number, port_settings) - elif mappings: - yield from device.set_mappings(mappings) - - response.set_status(201) - response.json(nio) - - @Route.delete( - r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/nio", - parameters={ - "project_id": "Project UUID", - "device_id": "Device UUID", - "port_number": "Port on the device" - }, - status_codes={ - 204: "NIO deleted", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Remove a NIO from a Dynamips device instance") - def delete_nio(request, response): - - dynamips_manager = Dynamips.instance() - device = dynamips_manager.get_device(request.match_info["device_id"], project_id=request.match_info["project_id"]) - port_number = int(request.match_info["port_number"]) - nio = yield from device.remove_nio(port_number) - yield from nio.delete() - response.set_status(204) - - @Route.post( - r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/start_capture", - parameters={ - "project_id": "Project UUID", - "device_id": "Device UUID", - "port_number": "Port on the device" - }, - status_codes={ - 200: "Capture started", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Start a packet capture on a Dynamips device instance", - input=NODE_CAPTURE_SCHEMA) - def start_capture(request, response): - - dynamips_manager = Dynamips.instance() - device = dynamips_manager.get_device(request.match_info["device_id"], project_id=request.match_info["project_id"]) - port_number = int(request.match_info["port_number"]) - pcap_file_path = os.path.join(device.project.capture_working_directory(), request.json["capture_file_name"]) - yield from device.start_capture(port_number, pcap_file_path, request.json["data_link_type"]) - response.json({"pcap_file_path": pcap_file_path}) - - @Route.post( - r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/stop_capture", - parameters={ - "project_id": "Project UUID", - "device_id": "Device UUID", - "port_number": "Port on the device" - }, - status_codes={ - 204: "Capture stopped", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Stop a packet capture on a Dynamips device instance") - def stop_capture(request, response): - - dynamips_manager = Dynamips.instance() - device = dynamips_manager.get_device(request.match_info["device_id"], project_id=request.match_info["project_id"]) - port_number = int(request.match_info["port_number"]) - yield from device.stop_capture(port_number) - response.set_status(204) diff --git a/gns3server/handlers/api/compute/ethernet_hub_handler.py b/gns3server/handlers/api/compute/ethernet_hub_handler.py index b8de5fe1..20ac5de1 100644 --- a/gns3server/handlers/api/compute/ethernet_hub_handler.py +++ b/gns3server/handlers/api/compute/ethernet_hub_handler.py @@ -140,6 +140,57 @@ class EthernetHubHandler: # yield from builtin_manager.delete_node(request.match_info["node_id"]) response.set_status(204) + @Route.post( + r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/start", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance started", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Start an Ethernet hub") + def start(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/stop", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance stopped", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Stop an Ethernet hub") + def stop(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/suspend", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance suspended", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Suspend an Ethernet hub") + def suspend(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + @Route.post( r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", parameters={ diff --git a/gns3server/handlers/api/compute/ethernet_switch_handler.py b/gns3server/handlers/api/compute/ethernet_switch_handler.py index 1435b042..8e238567 100644 --- a/gns3server/handlers/api/compute/ethernet_switch_handler.py +++ b/gns3server/handlers/api/compute/ethernet_switch_handler.py @@ -141,6 +141,57 @@ class EthernetSwitchHandler: # yield from builtin_manager.delete_node(request.match_info["node_id"]) response.set_status(204) + @Route.post( + r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/start", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance started", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Start an Ethernet switch") + def start(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/stop", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance stopped", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Stop an Ethernet switch") + def stop(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/suspend", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance suspended", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Suspend an Ethernet switch") + def suspend(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + @Route.post( r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", parameters={ @@ -163,10 +214,7 @@ class EthernetSwitchHandler: node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) nio = yield from dynamips_manager.create_nio(node, request.json) port_number = int(request.match_info["port_number"]) - #port_settings = request.json.get("port_settings") yield from node.add_nio(nio, port_number) - #if port_settings: - # yield from node.set_port_settings(port_number, port_settings) #builtin_manager = Builtin.instance() #node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) diff --git a/gns3server/handlers/api/compute/frame_relay_switch_handler.py b/gns3server/handlers/api/compute/frame_relay_switch_handler.py new file mode 100644 index 00000000..980c4ef6 --- /dev/null +++ b/gns3server/handlers/api/compute/frame_relay_switch_handler.py @@ -0,0 +1,270 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2015 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 . + +import os + +from gns3server.web.route import Route +from gns3server.schemas.node import NODE_CAPTURE_SCHEMA +from gns3server.schemas.nio import NIO_SCHEMA +from gns3server.compute.dynamips import Dynamips + +from gns3server.schemas.frame_relay_switch import ( + FRAME_RELAY_SWITCH_CREATE_SCHEMA, + FRAME_RELAY_SWITCH_OBJECT_SCHEMA, + FRAME_RELAY_SWITCH_UPDATE_SCHEMA +) + + +class FrameRelaySwitchHandler: + + """ + API entry points for Frame Relay switch. + """ + + @Route.post( + r"/projects/{project_id}/frame_relay_switch/nodes", + parameters={ + "project_id": "Project UUID" + }, + status_codes={ + 201: "Instance created", + 400: "Invalid request", + 409: "Conflict" + }, + description="Create a new Frame Relay switch instance", + input=FRAME_RELAY_SWITCH_CREATE_SCHEMA, + output=FRAME_RELAY_SWITCH_OBJECT_SCHEMA) + def create(request, response): + + # Use the Dynamips Frame Relay switch to simulate this node + dynamips_manager = Dynamips.instance() + node = yield from dynamips_manager.create_device(request.json.pop("name"), + request.match_info["project_id"], + request.json.get("node_id"), + device_type="frame_relay_switch", + mappings=request.json.get("mappings")) + response.set_status(201) + response.json(node) + + @Route.get( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 200: "Success", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Get a Frame Relay switch instance", + output=FRAME_RELAY_SWITCH_OBJECT_SCHEMA) + def show(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.json(node) + + @Route.put( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 200: "Instance updated", + 400: "Invalid request", + 404: "Instance doesn't exist", + 409: "Conflict" + }, + description="Update a Frame Relay switch instance", + input=FRAME_RELAY_SWITCH_UPDATE_SCHEMA, + output=FRAME_RELAY_SWITCH_OBJECT_SCHEMA) + def update(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + if "name" in request.json and node.name != request.json["name"]: + yield from node.set_name(request.json["name"]) + if "mappings" in request.json: + node.mappings = request.json["mappings"] + node.updated() + response.json(node) + + @Route.delete( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance deleted", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Delete a Frame Relay switch instance") + def delete(request, response): + + dynamips_manager = Dynamips.instance() + yield from dynamips_manager.delete_device(request.match_info["node_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/start", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance started", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Start a Frame Relay switch") + def start(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/stop", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance stopped", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Stop a Frame Relay switch") + def stop(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/suspend", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID" + }, + status_codes={ + 204: "Instance suspended", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Suspend a Frame Relay switch") + def suspend(request, response): + + Dynamips.instance().get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID", + "adapter_number": "Adapter on the switch (always 0)", + "port_number": "Port on the switch" + }, + status_codes={ + 201: "NIO created", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Add a NIO to a Frame Relay switch instance", + input=NIO_SCHEMA, + output=NIO_SCHEMA) + def create_nio(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + nio = yield from dynamips_manager.create_nio(node, request.json) + port_number = int(request.match_info["port_number"]) + yield from node.add_nio(nio, port_number) + response.set_status(201) + response.json(nio) + + @Route.delete( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID", + "adapter_number": "Adapter on the switch (always 0)", + "port_number": "Port on the switch" + }, + status_codes={ + 204: "NIO deleted", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Remove a NIO from a Frame Relay switch instance") + def delete_nio(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + port_number = int(request.match_info["port_number"]) + nio = yield from node.remove_nio(port_number) + yield from nio.delete() + response.set_status(204) + + @Route.post( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID", + "adapter_number": "Adapter on the switch (always 0)", + "port_number": "Port on the switch" + }, + status_codes={ + 200: "Capture started", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Start a packet capture on a Frame Relay switch instance", + input=NODE_CAPTURE_SCHEMA) + def start_capture(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + port_number = int(request.match_info["port_number"]) + pcap_file_path = os.path.join(node.project.capture_working_directory(), request.json["capture_file_name"]) + yield from node.start_capture(port_number, pcap_file_path, request.json["data_link_type"]) + response.json({"pcap_file_path": pcap_file_path}) + + @Route.post( + r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture", + parameters={ + "project_id": "Project UUID", + "node_id": "Node UUID", + "adapter_number": "Adapter on the switch (always 0)", + "port_number": "Port on the switch" + }, + status_codes={ + 204: "Capture stopped", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Stop a packet capture on a Frame Relay switch instance") + def stop_capture(request, response): + + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + port_number = int(request.match_info["port_number"]) + yield from node.stop_capture(port_number) + response.set_status(204) diff --git a/gns3server/schemas/atm_switch.py b/gns3server/schemas/atm_switch.py new file mode 100644 index 00000000..e6a12f97 --- /dev/null +++ b/gns3server/schemas/atm_switch.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2016 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 . + + +ATM_SWITCH_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, + }, + "node_id": { + "description": "Node UUID", + "oneOf": [ + {"type": "string", + "minLength": 36, + "maxLength": 36, + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"} + ] + }, + "mappings": { + "description": "ATM mappings", + "type": "object", + }, + }, + "additionalProperties": False, + "required": ["name"] +} + +ATM_SWITCH_OBJECT_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "ATM switch instance", + "type": "object", + "properties": { + "name": { + "description": "ATM switch name", + "type": "string", + "minLength": 1, + }, + "node_id": { + "description": "Node UUID", + "type": "string", + "minLength": 36, + "maxLength": 36, + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" + }, + "project_id": { + "description": "Project UUID", + "type": "string", + "minLength": 36, + "maxLength": 36, + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" + }, + "mappings": { + "description": "ATM mappings", + "type": "object", + }, + "status": { + "description": "Node status", + "enum": ["started", "stopped", "suspended"] + }, + }, + "additionalProperties": False, + "required": ["name", "node_id", "project_id"] +} + +ATM_SWITCH_UPDATE_SCHEMA = ATM_SWITCH_OBJECT_SCHEMA +del ATM_SWITCH_UPDATE_SCHEMA["required"] diff --git a/gns3server/schemas/dynamips_device.py b/gns3server/schemas/dynamips_device.py deleted file mode 100644 index 46ea6560..00000000 --- a/gns3server/schemas/dynamips_device.py +++ /dev/null @@ -1,348 +0,0 @@ -# -*- 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 . - - -DEVICE_CREATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to create a new Dynamips device instance", - "type": "object", - "properties": { - "name": { - "description": "Dynamips device name", - "type": "string", - "minLength": 1, - }, - "device_id": { - "description": "Dynamips device UUID", - "oneOf": [ - {"type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"}, - {"type": "integer"} # for legacy projects - ] - }, - "device_type": { - "description": "Dynamips device type", - "type": "string", - "minLength": 1, - }, - }, - "additionalProperties": False, - "required": ["name", "device_type"] -} - -DEVICE_UPDATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Dynamips device instance", - "type": "object", - "definitions": { - "EthernetSwitchPort": { - "description": "Ethernet switch port", - "properties": { - "port": { - "description": "Port number", - "type": "integer", - "minimum": 1 - }, - "type": { - "description": "Port type", - "enum": ["access", "dot1q", "qinq"], - }, - - "vlan": {"description": "VLAN number", - "type": "integer", - "minimum": 1 - }, - "ethertype": { - "description": "QinQ Ethertype", - "enum": ["", "0x8100", "0x88A8", "0x9100", "0x9200"], - }, - }, - "required": ["port", "type", "vlan"], - "additionalProperties": False - }, - }, - "properties": { - "name": { - "description": "Dynamips device instance name", - "type": "string", - "minLength": 1, - }, - "ports": { - "type": "array", - "items": [ - {"type": "object", - "oneOf": [ - {"$ref": "#/definitions/EthernetSwitchPort"} - ]}, - ] - } - }, - "additionalProperties": False, -} - -DEVICE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Dynamips device instance", - "type": "object", - "definitions": { - "EthernetSwitchPort": { - "description": "Ethernet switch port", - "properties": { - "port": { - "description": "Port number", - "type": "integer", - "minimum": 1 - }, - "type": { - "description": "Port type", - "enum": ["access", "dot1q", "qinq"], - }, - "vlan": {"description": "VLAN number", - "type": "integer", - "minimum": 1 - }, - "ethertype": { - "description": "QinQ Ethertype", - "enum": ["", "0x8100", "0x88A8", "0x9100", "0x9200"], - }, - }, - "required": ["port", "type", "vlan"], - "additionalProperties": False - }, - }, - "properties": { - "device_id": { - "description": "Dynamips router instance UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "project_id": { - "description": "Project UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "name": { - "description": "Dynamips device instance name", - "type": "string", - "minLength": 1, - }, - "ports": { - # only Ethernet switches have ports - "type": "array", - "items": [ - {"type": "object", - "oneOf": [ - {"$ref": "#/definitions/EthernetSwitchPort"} - ]}, - ] - }, - "mappings": { - # only Frame-Relay and ATM switches have mappings - "type": "object", - } - }, - "additionalProperties": False, - "required": ["name", "device_id", "project_id"] -} - -DEVICE_NIO_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to add a NIO for a Dynamips device 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 - }, - "NAT": { - "description": "NAT Network Input/Output", - "properties": { - "type": { - "enum": ["nio_nat"] - }, - }, - "required": ["type"], - "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": { - "nio": { - "type": "object", - "oneOf": [ - {"$ref": "#/definitions/UDP"}, - {"$ref": "#/definitions/Ethernet"}, - {"$ref": "#/definitions/LinuxEthernet"}, - {"$ref": "#/definitions/NAT"}, - {"$ref": "#/definitions/TAP"}, - {"$ref": "#/definitions/UNIX"}, - {"$ref": "#/definitions/VDE"}, - {"$ref": "#/definitions/NULL"}, - ] - }, - "port_settings": { - # only Ethernet switches have port settings - "type": "object", - "description": "Ethernet switch", - "properties": { - "type": { - "description": "Port type", - "enum": ["access", "dot1q", "qinq"], - }, - "vlan": {"description": "VLAN number", - "type": "integer", - "minimum": 1 - }, - "ethertype": { - "description": "QinQ Ethertype", - "enum": ["", "0x8100", "0x88A8", "0x9100", "0x9200"], - }, - }, - "required": ["type", "vlan"], - "additionalProperties": False - }, - "mappings": { - # only Frame-Relay and ATM switches have mappings - "type": "object", - } - }, - "additionalProperties": False, - "required": ["nio"] -} diff --git a/gns3server/schemas/frame_relay_switch.py b/gns3server/schemas/frame_relay_switch.py new file mode 100644 index 00000000..5d4967af --- /dev/null +++ b/gns3server/schemas/frame_relay_switch.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2016 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 . + + +FRAME_RELAY_SWITCH_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, + }, + "node_id": { + "description": "Node UUID", + "oneOf": [ + {"type": "string", + "minLength": 36, + "maxLength": 36, + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"} + ] + }, + "mappings": { + "description": "Frame Relay mappings", + "type": "object", + }, + }, + "additionalProperties": False, + "required": ["name"] +} + +FRAME_RELAY_SWITCH_OBJECT_SCHEMA = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Frame Relay switch instance", + "type": "object", + "properties": { + "name": { + "description": "Frame Relay switch name", + "type": "string", + "minLength": 1, + }, + "node_id": { + "description": "Node UUID", + "type": "string", + "minLength": 36, + "maxLength": 36, + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" + }, + "project_id": { + "description": "Project UUID", + "type": "string", + "minLength": 36, + "maxLength": 36, + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" + }, + "mappings": { + "description": "Frame Relay mappings", + "type": "object", + }, + "status": { + "description": "Node status", + "enum": ["started", "stopped", "suspended"] + }, + }, + "additionalProperties": False, + "required": ["name", "node_id", "project_id"] +} + +FRAME_RELAY_SWITCH_UPDATE_SCHEMA = FRAME_RELAY_SWITCH_OBJECT_SCHEMA +del FRAME_RELAY_SWITCH_UPDATE_SCHEMA["required"] diff --git a/gns3server/schemas/node.py b/gns3server/schemas/node.py index e48a9c1a..24dc4708 100644 --- a/gns3server/schemas/node.py +++ b/gns3server/schemas/node.py @@ -90,6 +90,8 @@ NODE_OBJECT_SCHEMA = { "description": "Type of node", "enum": ["ethernet_hub", "ethernet_switch", + "frame_relay_switch", + "atm_switch", "docker", "dynamips", "vpcs", diff --git a/gns3server/web/route.py b/gns3server/web/route.py index 1b32da14..570a6f4b 100644 --- a/gns3server/web/route.py +++ b/gns3server/web/route.py @@ -240,10 +240,8 @@ class Route(object): between the same instance of the node """ - if "node_id" in request.match_info or "device_id" in request.match_info: + if "node_id" in request.match_info: node_id = request.match_info.get("node_id") - if node_id is None: - node_id = request.match_info["device_id"] if "compute" in request.path: type = "compute"