From 7ebbdcd47c96a384e47b8c94205a82c22ca759c0 Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 17 May 2016 21:22:18 -0600 Subject: [PATCH] Functional Ethernet hub with new API. Uses Dynamips backend by default for now. --- .../compute/builtin/nodes/ethernet_hub.py | 188 +++++--------- gns3server/compute/dynamips/__init__.py | 4 +- ...s_device.py => dynamips_device_factory.py} | 2 +- .../compute/dynamips/nodes/ethernet_hub.py | 2 +- gns3server/controller/node.py | 2 +- .../api/compute/ethernet_hub_handler.py | 106 ++++---- .../handlers/api/controller/link_handler.py | 4 +- gns3server/schemas/ethernet_hub.py | 230 +----------------- gns3server/schemas/node.py | 2 +- 9 files changed, 138 insertions(+), 402 deletions(-) rename gns3server/compute/dynamips/{dynamips_device.py => dynamips_device_factory.py} (98%) diff --git a/gns3server/compute/builtin/nodes/ethernet_hub.py b/gns3server/compute/builtin/nodes/ethernet_hub.py index 70e434ea..fbc5f5b1 100644 --- a/gns3server/compute/builtin/nodes/ethernet_hub.py +++ b/gns3server/compute/builtin/nodes/ethernet_hub.py @@ -42,136 +42,68 @@ class EthernetHub(BaseNode): def __init__(self, name, node_id, project, manager): super().__init__(name, node_id, project, manager) - self._mappings = {} def __json__(self): return {"name": self.name, - "project_id": self.project.id, - "node_id": self.id} + "node_id": self.id, + "project_id": self.project.id} - # @asyncio.coroutine - # def create(self): - # - # yield from Bridge.create(self) - # log.info('Ethernet hub "{name}" [{id}] has been created'.format(name=self._name, id=self._id)) - # - # @property - # def mappings(self): - # """ - # Returns port mappings - # - # :returns: mappings list - # """ - # - # return self._mappings - # - # @asyncio.coroutine - # def delete(self): - # """ - # Deletes this hub. - # """ - # - # for nio in self._nios: - # if nio and isinstance(nio, NIOUDP): - # self.manager.port_manager.release_udp_port(nio.lport, self._project) - # - # try: - # yield from Bridge.delete(self) - # log.info('Ethernet hub "{name}" [{id}] has been deleted'.format(name=self._name, id=self._id)) - # except DynamipsError: - # log.debug("Could not properly delete Ethernet hub {}".format(self._name)) - # if self._hypervisor and not self._hypervisor.devices: - # yield from self.hypervisor.stop() - # - # @asyncio.coroutine - # def add_nio(self, nio, port_number): - # """ - # Adds a NIO as new port on this hub. - # - # :param nio: NIO instance to add - # :param port_number: port to allocate for the NIO - # """ - # - # if port_number in self._mappings: - # raise DynamipsError("Port {} isn't free".format(port_number)) - # - # yield from Bridge.add_nio(self, nio) - # - # log.info('Ethernet hub "{name}" [{id}]: NIO {nio} bound to port {port}'.format(name=self._name, - # id=self._id, - # nio=nio, - # port=port_number)) - # self._mappings[port_number] = nio - # - # @asyncio.coroutine - # def remove_nio(self, port_number): - # """ - # Removes the specified NIO as member of this hub. - # - # :param port_number: allocated port number - # - # :returns: the NIO that was bound to the allocated port - # """ - # - # if port_number not in self._mappings: - # raise DynamipsError("Port {} is not allocated".format(port_number)) - # - # nio = self._mappings[port_number] - # if isinstance(nio, NIOUDP): - # self.manager.port_manager.release_udp_port(nio.lport, self._project) - # yield from Bridge.remove_nio(self, nio) - # - # log.info('Ethernet switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name, - # id=self._id, - # nio=nio, - # port=port_number)) - # - # del self._mappings[port_number] - # return nio - # - # @asyncio.coroutine - # def start_capture(self, port_number, output_file, data_link_type="DLT_EN10MB"): - # """ - # Starts a packet capture. - # - # :param port_number: allocated port number - # :param output_file: PCAP destination file for the capture - # :param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB - # """ - # - # if port_number not in self._mappings: - # raise DynamipsError("Port {} is not allocated".format(port_number)) - # - # nio = self._mappings[port_number] - # - # data_link_type = data_link_type.lower() - # if data_link_type.startswith("dlt_"): - # data_link_type = data_link_type[4:] - # - # if nio.input_filter[0] is not None and nio.output_filter[0] is not None: - # raise DynamipsError("Port {} has already a filter applied".format(port_number)) - # - # yield from nio.bind_filter("both", "capture") - # yield from nio.setup_filter("both", '{} "{}"'.format(data_link_type, output_file)) - # - # log.info('Ethernet hub "{name}" [{id}]: starting packet capture on port {port}'.format(name=self._name, - # id=self._id, - # port=port_number)) - # - # @asyncio.coroutine - # def stop_capture(self, port_number): - # """ - # Stops a packet capture. - # - # :param port_number: allocated port number - # """ - # - # if port_number not in self._mappings: - # raise DynamipsError("Port {} is not allocated".format(port_number)) - # - # nio = self._mappings[port_number] - # yield from nio.unbind_filter("both") - # log.info('Ethernet hub "{name}" [{id}]: stopping packet capture on port {port}'.format(name=self._name, - # id=self._id, - # port=port_number)) + @asyncio.coroutine + def create(self): + + super().create() + log.info('Ethernet hub "{name}" [{id}] has been created'.format(name=self._name, id=self._id)) + + @asyncio.coroutine + def delete(self): + """ + Deletes this hub. + """ + + raise NotImplementedError() + + @asyncio.coroutine + def add_nio(self, nio, port_number): + """ + Adds a NIO as new port on this hub. + + :param nio: NIO instance to add + :param port_number: port to allocate for the NIO + """ + + raise NotImplementedError() + + @asyncio.coroutine + def remove_nio(self, port_number): + """ + Removes the specified NIO as member of this hub. + + :param port_number: allocated port number + + :returns: the NIO that was bound to the allocated port + """ + + raise NotImplementedError() + + @asyncio.coroutine + def start_capture(self, port_number, output_file, data_link_type="DLT_EN10MB"): + """ + Starts a packet capture. + + :param port_number: allocated port number + :param output_file: PCAP destination file for the capture + :param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB + """ + + raise NotImplementedError() + + @asyncio.coroutine + def stop_capture(self, port_number): + """ + Stops a packet capture. + + :param port_number: allocated port number + """ + + raise NotImplementedError() diff --git a/gns3server/compute/dynamips/__init__.py b/gns3server/compute/dynamips/__init__.py index 69c85fc4..c0dcf48a 100644 --- a/gns3server/compute/dynamips/__init__.py +++ b/gns3server/compute/dynamips/__init__.py @@ -43,7 +43,7 @@ from .dynamips_error import DynamipsError from .hypervisor import Hypervisor from .nodes.router import Router from .dynamips_vm_factory import DynamipsVMFactory -from .dynamips_device import DynamipsDevice +from .dynamips_device_factory import DynamipsDeviceFactory # NIOs from .nios.nio_udp import NIOUDP @@ -103,7 +103,7 @@ WIC_MATRIX = {"WIC-1ENET": WIC_1ENET, class Dynamips(BaseManager): _NODE_CLASS = DynamipsVMFactory - _DEVICE_CLASS = DynamipsDevice + _DEVICE_CLASS = DynamipsDeviceFactory _ghost_ios_lock = None def __init__(self): diff --git a/gns3server/compute/dynamips/dynamips_device.py b/gns3server/compute/dynamips/dynamips_device_factory.py similarity index 98% rename from gns3server/compute/dynamips/dynamips_device.py rename to gns3server/compute/dynamips/dynamips_device_factory.py index e8398c94..da44a55d 100644 --- a/gns3server/compute/dynamips/dynamips_device.py +++ b/gns3server/compute/dynamips/dynamips_device_factory.py @@ -31,7 +31,7 @@ DEVICES = {'atm_switch': ATMSwitch, 'ethernet_hub': EthernetHub} -class DynamipsDevice: +class DynamipsDeviceFactory: """ Factory to create an Device object based on the type diff --git a/gns3server/compute/dynamips/nodes/ethernet_hub.py b/gns3server/compute/dynamips/nodes/ethernet_hub.py index 776ec944..b76c9102 100644 --- a/gns3server/compute/dynamips/nodes/ethernet_hub.py +++ b/gns3server/compute/dynamips/nodes/ethernet_hub.py @@ -49,7 +49,7 @@ class EthernetHub(Bridge): def __json__(self): return {"name": self.name, - "device_id": self.id, + "node_id": self.id, "project_id": self.project.id} @asyncio.coroutine diff --git a/gns3server/controller/node.py b/gns3server/controller/node.py index a937fa04..38c4a3d1 100644 --- a/gns3server/controller/node.py +++ b/gns3server/controller/node.py @@ -153,8 +153,8 @@ class Node: data = copy.copy(self._properties) data["name"] = self._name if self._console: + # console is optional for builtin nodes data["console"] = self._console - if self._console_type: data["console_type"] = self._console_type # None properties are not be send. Because it can mean the emulator doesn't support it diff --git a/gns3server/handlers/api/compute/ethernet_hub_handler.py b/gns3server/handlers/api/compute/ethernet_hub_handler.py index 5caa23c0..ce28b0bd 100644 --- a/gns3server/handlers/api/compute/ethernet_hub_handler.py +++ b/gns3server/handlers/api/compute/ethernet_hub_handler.py @@ -19,13 +19,14 @@ 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.builtin import Builtin +from gns3server.compute.dynamips import Dynamips from gns3server.schemas.ethernet_hub import ( ETHERNET_HUB_CREATE_SCHEMA, ETHERNET_HUB_UPDATE_SCHEMA, - ETHERNET_HUB_OBJECT_SCHEMA, - ETHERNET_HUB_NIO_SCHEMA + ETHERNET_HUB_OBJECT_SCHEMA ) @@ -50,11 +51,19 @@ class EthernetHubHandler: output=ETHERNET_HUB_OBJECT_SCHEMA) def create(request, response): - builtin_manager = Builtin.instance() - node = yield from builtin_manager.create_node(request.json.pop("name"), - request.match_info["project_id"], - request.json.get("node_id"), - node_type="ethernet_hub") + # Use the Dynamips Ethernet hub 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="ethernet_hub") + + # On Linux, use the generic hub + # builtin_manager = Builtin.instance() + # node = yield from builtin_manager.create_node(request.json.pop("name"), + # request.match_info["project_id"], + # request.json.get("node_id"), + # node_type="ethernet_hub") response.set_status(201) response.json(node) @@ -74,8 +83,11 @@ class EthernetHubHandler: output=ETHERNET_HUB_OBJECT_SCHEMA) def show(request, response): - builtin_manager = Builtin.instance() - node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + + # builtin_manager = Builtin.instance() + # node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) response.json(node) @Route.put( @@ -95,16 +107,11 @@ class EthernetHubHandler: output=ETHERNET_HUB_OBJECT_SCHEMA) def update(request, response): - builtin_manager = Builtin.instance() - node = builtin_manager.get_node(request.match_info["node_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) + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + # builtin_manager = Builtin.instance() + # node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) response.json(node) @Route.delete( @@ -121,16 +128,18 @@ class EthernetHubHandler: description="Delete an Ethernet hub instance") def delete(request, response): - builtin_manager = Builtin.instance() - yield from builtin_manager.delete_node(request.match_info["node_id"]) + dynamips_manager = Dynamips.instance() + yield from dynamips_manager.delete_device(request.match_info["node_id"]) + # builtin_manager = Builtin.instance() + # yield from builtin_manager.delete_node(request.match_info["node_id"]) response.set_status(204) - # FIXME: introduce adapter number (always 0)? @Route.post( - r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/ports/{port_number:\d+}/nio", + r"/projects/{project_id}/ethernet_hub/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 hub (always 0)", "port_number": "Port on the hub" }, status_codes={ @@ -139,31 +148,32 @@ class EthernetHubHandler: 404: "Instance doesn't exist" }, description="Add a NIO to an Ethernet hub instance", - input=ETHERNET_HUB_NIO_SCHEMA) + input=NIO_SCHEMA, + output=NIO_SCHEMA) def create_nio(request, response): - builtin_manager = Builtin.instance() - node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) - nio = yield from builtin_manager.create_nio(node, request.json["nio"]) + 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"]) - # port_settings = request.json.get("port_settings") - # - # if asyncio.iscoroutinefunction(node.add_nio): - # yield from node.add_nio(nio, port_number) - # else: - # node.add_nio(nio, port_number) - # - # if port_settings: - # yield from node.set_port_settings(port_number, port_settings) + 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"]) + #nio = yield from builtin_manager.create_nio(node, request.json["nio"]) response.set_status(201) response.json(nio) @Route.delete( - r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/ports/{port_number:\d+}/nio", + r"/projects/{project_id}/ethernet_hub/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 hub (always 0)", "port_number": "Port on the hub" }, status_codes={ @@ -174,18 +184,21 @@ class EthernetHubHandler: description="Remove a NIO from an Ethernet hub instance") def delete_nio(request, response): - builtin_manager = Builtin.instance() - node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + #builtin_manager = Builtin.instance() + #node = builtin_manager.get_node(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}/ethernet_hub/nodes/{node_id}/ports/{port_number:\d+}/start_capture", + r"/projects/{project_id}/ethernet_hub/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 hub (always 0)", "port_number": "Port on the hub" }, status_codes={ @@ -197,18 +210,21 @@ class EthernetHubHandler: input=NODE_CAPTURE_SCHEMA) def start_capture(request, response): - builtin_manager = Builtin.instance() - node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + #builtin_manager = Builtin.instance() + #node = builtin_manager.get_node(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}/ethernet_hub/nodes/{node_id}/ports/{port_number:\d+}/stop_capture", + r"/projects/{project_id}/ethernet_hub/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 hub (always 0)", "port_number": "Port on the hub" }, status_codes={ @@ -219,8 +235,10 @@ class EthernetHubHandler: description="Stop a packet capture on an Ethernet hub instance") def stop_capture(request, response): - builtin_manager = Builtin.instance() - node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) + dynamips_manager = Dynamips.instance() + node = dynamips_manager.get_device(request.match_info["node_id"], project_id=request.match_info["project_id"]) + #builtin_manager = Builtin.instance() + #node = builtin_manager.get_node(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/controller/link_handler.py b/gns3server/handlers/api/controller/link_handler.py index d2be92bf..3d227c5b 100644 --- a/gns3server/handlers/api/controller/link_handler.py +++ b/gns3server/handlers/api/controller/link_handler.py @@ -64,7 +64,9 @@ class LinkHandler: project = controller.get_project(request.match_info["project_id"]) link = yield from project.add_link() for node in request.json["nodes"]: - yield from link.add_node(project.get_node(node["node_id"]), node["adapter_number"], node["port_number"]) + yield from link.add_node(project.get_node(node["node_id"]), + node.get("adapter_number", 0), + node.get("port_number", 0)) yield from link.create() response.set_status(201) response.json(link) diff --git a/gns3server/schemas/ethernet_hub.py b/gns3server/schemas/ethernet_hub.py index 8320f6cd..b91725dd 100644 --- a/gns3server/schemas/ethernet_hub.py +++ b/gns3server/schemas/ethernet_hub.py @@ -40,17 +40,17 @@ ETHERNET_HUB_CREATE_SCHEMA = { "required": ["name"] } -ETHERNET_HUB_UPDATE_SCHEMA = { +ETHERNET_HUB_OBJECT_SCHEMA = { "$schema": "http://json-schema.org/draft-04/schema#", "description": "Ethernet hub instance", "type": "object", "definitions": { - "EthernetSwitchPort": { - "description": "Ethernet switch port", + "EthernetPort": { + "description": "Ethernet port", "properties": { "port": { "description": "Port number", - "type": "number", + "type": "integer", "minimum": 1 }, }, @@ -64,38 +64,6 @@ ETHERNET_HUB_UPDATE_SCHEMA = { "type": "string", "minLength": 1, }, - "ports": { - "type": "array", - "items": [ - {"type": "object", - "oneOf": [ - {"$ref": "#/definitions/EthernetSwitchPort"} - ]}, - ] - } - }, - "additionalProperties": False, -} - -ETHERNET_HUB_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Ethernet hub instance", - "type": "object", - "definitions": { - "EthernetSwitchPort": { - "description": "Ethernet switch port", - "properties": { - "port": { - "description": "Port number", - "type": "integer", - "minimum": 1 - }, - }, - "required": ["port"], - "additionalProperties": False - }, - }, - "properties": { "node_id": { "description": "Node UUID", "type": "string", @@ -110,17 +78,12 @@ ETHERNET_HUB_OBJECT_SCHEMA = { "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": "Ethernet hub name", - "type": "string", - "minLength": 1, - }, "ports": { "type": "array", "items": [ {"type": "object", "oneOf": [ - {"$ref": "#/definitions/EthernetSwitchPort"} + {"$ref": "#/definitions/EthernetPort"} ]}, ] } @@ -129,184 +92,5 @@ ETHERNET_HUB_OBJECT_SCHEMA = { "required": ["name", "node_id", "project_id"] } -ETHERNET_HUB_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 - }, - "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"] -} +ETHERNET_HUB_UPDATE_SCHEMA = ETHERNET_HUB_OBJECT_SCHEMA +del ETHERNET_HUB_UPDATE_SCHEMA["required"] diff --git a/gns3server/schemas/node.py b/gns3server/schemas/node.py index bd1f3fdf..8d91efd8 100644 --- a/gns3server/schemas/node.py +++ b/gns3server/schemas/node.py @@ -119,7 +119,7 @@ NODE_OBJECT_SCHEMA = { }, "status": { "description": "Status of the node", - "enum": ["stopped", "started"] + "enum": ["stopped", "started", "suspended"] } }, "additionalProperties": False,