diff --git a/gns3server/compute/builtin/builtin_node_factory.py b/gns3server/compute/builtin/builtin_node_factory.py
index 9f9e2285..d7f234f4 100644
--- a/gns3server/compute/builtin/builtin_node_factory.py
+++ b/gns3server/compute/builtin/builtin_node_factory.py
@@ -18,11 +18,13 @@
from ..node_error import NodeError
from .nodes.ethernet_hub import EthernetHub
+from .nodes.ethernet_switch import EthernetSwitch
import logging
log = logging.getLogger(__name__)
-BUILTIN_NODES = {'ethernet_hub': EthernetHub}
+BUILTIN_NODES = {'ethernet_hub': EthernetHub,
+ 'ethernet_switch': EthernetSwitch}
class BuiltinNodeFactory:
diff --git a/gns3server/compute/builtin/nodes/ethernet_switch.py b/gns3server/compute/builtin/nodes/ethernet_switch.py
new file mode 100644
index 00000000..16afbc10
--- /dev/null
+++ b/gns3server/compute/builtin/nodes/ethernet_switch.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013 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 .
+
+"""
+Hub object that uses the Bridge interface to create a hub with ports.
+"""
+
+import asyncio
+
+from ...node_error import NodeError
+from ...base_node import BaseNode
+
+import logging
+log = logging.getLogger(__name__)
+
+
+class EthernetSwitch(BaseNode):
+
+ """
+ Ethernet switch.
+
+ :param name: name for this switch
+ :param node_id: Node identifier
+ :param project: Project instance
+ :param manager: Parent VM Manager
+ """
+
+ def __init__(self, name, node_id, project, manager):
+
+ super().__init__(name, node_id, project, manager)
+
+ def __json__(self):
+
+ return {"name": self.name,
+ "node_id": self.id,
+ "project_id": self.project.id}
+
+ @asyncio.coroutine
+ def create(self):
+
+ super().create()
+ log.info('Ethernet switch "{name}" [{id}] has been created'.format(name=self._name, id=self._id))
+
+ @asyncio.coroutine
+ def delete(self):
+ """
+ Deletes this switch.
+ """
+
+ raise NotImplementedError()
+
+ @asyncio.coroutine
+ def add_nio(self, nio, port_number):
+ """
+ Adds a NIO as new port on this switch.
+
+ :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 switch.
+
+ :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 70ac1d1f..27948622 100644
--- a/gns3server/compute/dynamips/__init__.py
+++ b/gns3server/compute/dynamips/__init__.py
@@ -266,32 +266,33 @@ class Dynamips(BaseManager):
return self._dynamips_path
@asyncio.coroutine
- def create_device(self, name, project_id, device_id, device_type, *args, **kwargs):
+ def create_device(self, name, project_id, node_id, device_type, *args, **kwargs):
"""
Create a new Dynamips device.
:param name: Device name
:param project_id: Project identifier
+ :param node_id: Node identifier
"""
project = ProjectManager.instance().get_project(project_id)
- if device_id and isinstance(device_id, int):
+ if node_id and isinstance(node_id, int):
with (yield from BaseManager._convert_lock):
- device_id = yield from self.convert_old_project(project, device_id, name)
+ node_id = yield from self.convert_old_project(project, node_id, name)
- if not device_id:
- device_id = str(uuid4())
+ if not node_id:
+ node_id = str(uuid4())
- device = self._DEVICE_CLASS(name, device_id, project, self, device_type, *args, **kwargs)
+ device = self._DEVICE_CLASS(name, node_id, project, self, device_type, *args, **kwargs)
yield from device.create()
self._devices[device.id] = device
return device
- def get_device(self, device_id, project_id=None):
+ def get_device(self, node_id, project_id=None):
"""
Returns a device instance.
- :param device_id: Device identifier
+ :param node_id: Node identifier
:param project_id: Project identifier
:returns: Device instance
@@ -302,14 +303,14 @@ class Dynamips(BaseManager):
project = ProjectManager.instance().get_project(project_id)
try:
- UUID(device_id, version=4)
+ UUID(node_id, version=4)
except ValueError:
- raise aiohttp.web.HTTPBadRequest(text="Device ID} is not a valid UUID".format(device_id))
+ raise aiohttp.web.HTTPBadRequest(text="Node ID {} is not a valid UUID".format(node_id))
- if device_id not in self._devices:
- raise aiohttp.web.HTTPNotFound(text="Device ID {} doesn't exist".format(device_id))
+ if node_id not in self._devices:
+ raise aiohttp.web.HTTPNotFound(text="Node ID {} doesn't exist".format(node_id))
- device = self._devices[device_id]
+ device = self._devices[node_id]
if project_id:
if device.project.id != project.id:
raise aiohttp.web.HTTPNotFound(text="Project ID {} doesn't belong to device {}".format(project_id, device.name))
@@ -317,16 +318,16 @@ class Dynamips(BaseManager):
return device
@asyncio.coroutine
- def delete_device(self, device_id):
+ def delete_device(self, node_id):
"""
Delete a device
- :param device_id: Device identifier
+ :param node_id: Node identifier
:returns: Device instance
"""
- device = self.get_device(device_id)
+ device = self.get_device(node_id)
yield from device.delete()
del self._devices[device.id]
return device
diff --git a/gns3server/compute/dynamips/nodes/device.py b/gns3server/compute/dynamips/nodes/device.py
index 373af5f2..9b0577ee 100644
--- a/gns3server/compute/dynamips/nodes/device.py
+++ b/gns3server/compute/dynamips/nodes/device.py
@@ -28,10 +28,10 @@ class Device:
:param hypervisor: Dynamips hypervisor instance
"""
- def __init__(self, name, device_id, project, manager, hypervisor=None):
+ def __init__(self, name, node_id, project, manager, hypervisor=None):
self._name = name
- self._id = device_id
+ self._id = node_id
self._project = project
self._manager = manager
self._hypervisor = hypervisor
@@ -96,6 +96,12 @@ class Device:
return self._manager
+ def updated(self):
+ """
+ Send a updated event
+ """
+ self.project.emit("node.updated", self)
+
def create(self):
"""
Creates the device.
diff --git a/gns3server/compute/dynamips/nodes/ethernet_hub.py b/gns3server/compute/dynamips/nodes/ethernet_hub.py
index b76c9102..1e135926 100644
--- a/gns3server/compute/dynamips/nodes/ethernet_hub.py
+++ b/gns3server/compute/dynamips/nodes/ethernet_hub.py
@@ -35,22 +35,53 @@ class EthernetHub(Bridge):
Dynamips Ethernet hub (based on Bridge)
:param name: name for this hub
- :param device_id: Device instance identifier
+ :param node_id: Node instance identifier
:param project: Project instance
:param manager: Parent VM Manager
+ :param ports: initial hub ports
:param hypervisor: Dynamips hypervisor instance
"""
- def __init__(self, name, device_id, project, manager, hypervisor=None):
+ def __init__(self, name, node_id, project, manager, ports=None, hypervisor=None):
- super().__init__(name, device_id, project, manager, hypervisor)
+ super().__init__(name, node_id, project, manager, hypervisor)
self._mappings = {}
+ if ports is None:
+ # create 8 ports by default
+ self._ports = []
+ for port_number in range(1, 9):
+ self._ports.append({"port_number": port_number,
+ "name": "Ethernet{}".format(port_number)})
+ else:
+ self._ports = ports
def __json__(self):
return {"name": self.name,
"node_id": self.id,
- "project_id": self.project.id}
+ "project_id": self.project.id,
+ "ports": self._ports,
+ "status": "started"}
+
+ @property
+ def ports(self):
+ """
+ Ports on this hub
+
+ :returns: ports info
+ """
+
+ return self._ports
+
+ @ports.setter
+ def ports(self, ports):
+ """
+ Set the ports on this hub
+
+ :param ports: ports info
+ """
+
+ self._ports = ports
@asyncio.coroutine
def create(self):
@@ -95,6 +126,9 @@ class EthernetHub(Bridge):
:param port_number: port to allocate for the NIO
"""
+ if port_number not in [port["port_number"] for port in self._ports]:
+ raise DynamipsError("Port {} doesn't exist".format(port_number))
+
if port_number in self._mappings:
raise DynamipsError("Port {} isn't free".format(port_number))
diff --git a/gns3server/compute/dynamips/nodes/ethernet_switch.py b/gns3server/compute/dynamips/nodes/ethernet_switch.py
index b6e96977..07f0e522 100644
--- a/gns3server/compute/dynamips/nodes/ethernet_switch.py
+++ b/gns3server/compute/dynamips/nodes/ethernet_switch.py
@@ -37,34 +37,67 @@ class EthernetSwitch(Device):
Dynamips Ethernet 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 ports: initial switch ports
:param hypervisor: Dynamips hypervisor instance
"""
- def __init__(self, name, device_id, project, manager, hypervisor=None):
+ def __init__(self, name, node_id, project, manager, ports=None, hypervisor=None):
- super().__init__(name, device_id, project, manager, hypervisor)
+ super().__init__(name, node_id, project, manager, hypervisor)
self._nios = {}
self._mappings = {}
+ if ports is None:
+ # create 8 ports by default
+ self._ports = []
+ for port_number in range(1, 9):
+ self._ports.append({"port_number": port_number,
+ "name": "Ethernet{}".format(port_number),
+ "type": "access",
+ "vlan": 1})
+ else:
+ self._ports = ports
def __json__(self):
ethernet_switch_info = {"name": self.name,
- "device_id": self.id,
- "project_id": self.project.id}
+ "node_id": self.id,
+ "project_id": self.project.id,
+ "ports": self._ports,
+ "status": "started"}
- ports = []
- for port_number, settings in self._mappings.items():
- ports.append({"port": port_number,
- "type": settings[0],
- "vlan": settings[1],
- "ethertype": settings[2] if len(settings) > 2 else ""})
-
- ethernet_switch_info["ports"] = ports
+ # ports = []
+ # for port_number, settings in self._mappings.items():
+ # ports.append({"port": port_number,
+ # "type": settings[0],
+ # "vlan": settings[1],
+ # "ethertype": settings[2] if len(settings) > 2 else ""})
+ #
+ # ethernet_switch_info["ports"] = ports
return ethernet_switch_info
+ @property
+ def ports(self):
+ """
+ Ports on this switch
+
+ :returns: ports info
+ """
+
+ return self._ports
+
+ @ports.setter
+ def ports(self, ports):
+ """
+ Set the ports on this switch
+
+ :param ports: ports info
+ """
+
+ self._ports = ports
+
@asyncio.coroutine
def create(self):
@@ -149,6 +182,10 @@ class EthernetSwitch(Device):
nio=nio,
port=port_number))
self._nios[port_number] = nio
+ for port_settings in self._ports:
+ if port_settings["port_number"] == port_number:
+ yield from self.set_port_settings(port_number, port_settings)
+ break
@asyncio.coroutine
def remove_nio(self, port_number):
diff --git a/gns3server/controller/node.py b/gns3server/controller/node.py
index b2b6bab5..3d37354b 100644
--- a/gns3server/controller/node.py
+++ b/gns3server/controller/node.py
@@ -105,7 +105,7 @@ class Node:
self.parse_node_response(response.json)
@asyncio.coroutine
- def update(self, name=None, console=None, console_type="telnet", properties={}):
+ def update(self, name=None, console=None, console_type=None, properties={}):
"""
Update the node on the compute server
diff --git a/gns3server/handlers/api/compute/__init__.py b/gns3server/handlers/api/compute/__init__.py
index 64614935..ca5c61f8 100644
--- a/gns3server/handlers/api/compute/__init__.py
+++ b/gns3server/handlers/api/compute/__init__.py
@@ -30,9 +30,10 @@ from .config_handler import ConfigHandler
from .version_handler import VersionHandler
from .notification_handler import NotificationHandler
from .ethernet_hub_handler import EthernetHubHandler
+from .ethernet_switch_handler import EthernetSwitchHandler
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 testsuite work on UNIX platform
+ # IOU runs only on Linux but test suite works on UNIX platform
if not sys.platform.startswith("win"):
from .iou_handler import IOUHandler
from .docker_handler import DockerHandler
diff --git a/gns3server/handlers/api/compute/ethernet_hub_handler.py b/gns3server/handlers/api/compute/ethernet_hub_handler.py
index 583c4152..b8de5fe1 100644
--- a/gns3server/handlers/api/compute/ethernet_hub_handler.py
+++ b/gns3server/handlers/api/compute/ethernet_hub_handler.py
@@ -56,7 +56,8 @@ class EthernetHubHandler:
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")
+ device_type="ethernet_hub",
+ ports=request.json.get("ports"))
# On Linux, use the generic hub
# builtin_manager = Builtin.instance()
@@ -109,6 +110,10 @@ class EthernetHubHandler:
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 "ports" in request.json:
+ node.ports = request.json["ports"]
# builtin_manager = Builtin.instance()
# node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
@@ -157,10 +162,7 @@ class EthernetHubHandler:
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/ethernet_switch_handler.py b/gns3server/handlers/api/compute/ethernet_switch_handler.py
new file mode 100644
index 00000000..1435b042
--- /dev/null
+++ b/gns3server/handlers/api/compute/ethernet_switch_handler.py
@@ -0,0 +1,251 @@
+# -*- 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.builtin import Builtin
+from gns3server.compute.dynamips import Dynamips
+
+from gns3server.schemas.ethernet_switch import (
+ ETHERNET_SWITCH_CREATE_SCHEMA,
+ ETHERNET_SWITCH_UPDATE_SCHEMA,
+ ETHERNET_SWITCH_OBJECT_SCHEMA
+)
+
+
+class EthernetSwitchHandler:
+
+ """
+ API entry points for Ethernet switch.
+ """
+
+ @Route.post(
+ r"/projects/{project_id}/ethernet_switch/nodes",
+ parameters={
+ "project_id": "Project UUID"
+ },
+ status_codes={
+ 201: "Instance created",
+ 400: "Invalid request",
+ 409: "Conflict"
+ },
+ description="Create a new Ethernet switch instance",
+ input=ETHERNET_SWITCH_CREATE_SCHEMA,
+ output=ETHERNET_SWITCH_OBJECT_SCHEMA)
+ def create(request, response):
+
+ # Use the Dynamips Ethernet 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="ethernet_switch",
+ ports=request.json.get("ports"))
+
+ # On Linux, use the generic switch
+ # 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_switch")
+
+ response.set_status(201)
+ response.json(node)
+
+ @Route.get(
+ r"/projects/{project_id}/ethernet_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 Ethernet switch instance",
+ output=ETHERNET_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"])
+
+ # 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(
+ r"/projects/{project_id}/ethernet_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 Ethernet switch instance",
+ input=ETHERNET_SWITCH_UPDATE_SCHEMA,
+ output=ETHERNET_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 "ports" in request.json:
+ node.ports = request.json["ports"]
+
+ # builtin_manager = Builtin.instance()
+ # node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
+
+ node.updated()
+ response.json(node)
+
+ @Route.delete(
+ r"/projects/{project_id}/ethernet_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 Ethernet switch instance")
+ def delete(request, response):
+
+ 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)
+
+ @Route.post(
+ r"/projects/{project_id}/ethernet_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 Ethernet 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"])
+ #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_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 Ethernet 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"])
+ #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_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 Ethernet 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"])
+ #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_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 Ethernet 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"])
+ #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/schemas/ethernet_hub.py b/gns3server/schemas/ethernet_hub.py
index b91725dd..5f0ac71b 100644
--- a/gns3server/schemas/ethernet_hub.py
+++ b/gns3server/schemas/ethernet_hub.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2014 GNS3 Technologies Inc.
+# 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
@@ -20,6 +20,25 @@ ETHERNET_HUB_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new Ethernet hub instance",
"type": "object",
+ "definitions": {
+ "EthernetHubPort": {
+ "description": "Ethernet port",
+ "properties": {
+ "name": {
+ "description": "Port name",
+ "type": "string",
+ "minLength": 1,
+ },
+ "port_number": {
+ "description": "Port number",
+ "type": "integer",
+ "minimum": 1
+ },
+ },
+ "required": ["name", "port_number"],
+ "additionalProperties": False
+ },
+ },
"properties": {
"name": {
"description": "Ethernet hub name",
@@ -34,7 +53,16 @@ ETHERNET_HUB_CREATE_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}$"}
]
- }
+ },
+ "ports": {
+ "type": "array",
+ "items": [
+ {"type": "object",
+ "oneOf": [
+ {"$ref": "#/definitions/EthernetHubPort"}
+ ]},
+ ]
+ },
},
"additionalProperties": False,
"required": ["name"]
@@ -45,16 +73,21 @@ ETHERNET_HUB_OBJECT_SCHEMA = {
"description": "Ethernet hub instance",
"type": "object",
"definitions": {
- "EthernetPort": {
+ "EthernetHubPort": {
"description": "Ethernet port",
"properties": {
- "port": {
+ "name": {
+ "description": "Port name",
+ "type": "string",
+ "minLength": 1,
+ },
+ "port_number": {
"description": "Port number",
"type": "integer",
"minimum": 1
},
},
- "required": ["port"],
+ "required": ["name", "port_number"],
"additionalProperties": False
},
},
@@ -83,13 +116,17 @@ ETHERNET_HUB_OBJECT_SCHEMA = {
"items": [
{"type": "object",
"oneOf": [
- {"$ref": "#/definitions/EthernetPort"}
+ {"$ref": "#/definitions/EthernetHubPort"}
]},
]
- }
+ },
+ "status": {
+ "description": "Node status",
+ "enum": ["started", "stopped", "suspended"]
+ },
},
"additionalProperties": False,
- "required": ["name", "node_id", "project_id"]
+ "required": ["name", "node_id", "project_id", "ports"]
}
ETHERNET_HUB_UPDATE_SCHEMA = ETHERNET_HUB_OBJECT_SCHEMA
diff --git a/gns3server/schemas/ethernet_switch.py b/gns3server/schemas/ethernet_switch.py
new file mode 100644
index 00000000..83554749
--- /dev/null
+++ b/gns3server/schemas/ethernet_switch.py
@@ -0,0 +1,157 @@
+# -*- 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 .
+
+
+ETHERNET_SWITCH_CREATE_SCHEMA = {
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "description": "Request validation to create a new Ethernet switch instance",
+ "type": "object",
+ "definitions": {
+ "EthernetSwitchPort": {
+ "description": "Ethernet port",
+ "properties": {
+ "name": {
+ "description": "Port name",
+ "type": "string",
+ "minLength": 1,
+ },
+ "port_number": {
+ "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": ["name", "port_number", "type"],
+ "additionalProperties": False
+ },
+ },
+ "properties": {
+ "name": {
+ "description": "Ethernet 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}$"}
+ ]
+ },
+ "ports": {
+ "type": "array",
+ "items": [
+ {"type": "object",
+ "oneOf": [
+ {"$ref": "#/definitions/EthernetSwitchPort"}
+ ]},
+ ]
+ },
+ },
+ "additionalProperties": False,
+ "required": ["name"]
+}
+
+ETHERNET_SWITCH_OBJECT_SCHEMA = {
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "description": "Ethernet switch instance",
+ "type": "object",
+ "definitions": {
+ "EthernetSwitchPort": {
+ "description": "Ethernet port",
+ "properties": {
+ "name": {
+ "description": "Port name",
+ "type": "string",
+ "minLength": 1,
+ },
+ "port_number": {
+ "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": ["name", "port_number", "type"],
+ "additionalProperties": False
+ },
+ },
+ "properties": {
+ "name": {
+ "description": "Ethernet 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}$"
+ },
+ "ports": {
+ "type": "array",
+ "items": [
+ {"type": "object",
+ "oneOf": [
+ {"$ref": "#/definitions/EthernetSwitchPort"}
+ ]},
+ ]
+ },
+ "status": {
+ "description": "Node status",
+ "enum": ["started", "stopped", "suspended"]
+ },
+ },
+ "additionalProperties": False,
+ "required": ["name", "node_id", "project_id"]
+}
+
+ETHERNET_SWITCH_UPDATE_SCHEMA = ETHERNET_SWITCH_OBJECT_SCHEMA
+del ETHERNET_SWITCH_UPDATE_SCHEMA["required"]
diff --git a/gns3server/schemas/node.py b/gns3server/schemas/node.py
index c2edce9e..e48a9c1a 100644
--- a/gns3server/schemas/node.py
+++ b/gns3server/schemas/node.py
@@ -88,7 +88,15 @@ NODE_OBJECT_SCHEMA = {
},
"node_type": {
"description": "Type of node",
- "enum": ["ethernet_hub", "docker", "dynamips", "vpcs", "virtualbox", "vmware", "iou", "qemu"]
+ "enum": ["ethernet_hub",
+ "ethernet_switch",
+ "docker",
+ "dynamips",
+ "vpcs",
+ "virtualbox",
+ "vmware",
+ "iou",
+ "qemu"]
},
"node_directory": {
"description": "Working directory of the node. Read only",