1
0
mirror of https://github.com/GNS3/gns3-server synced 2025-02-17 18:42:00 +00:00

Base for generic switch nodes. Ref #492.

This commit is contained in:
grossmj 2016-05-15 11:23:14 -06:00
parent 5b604da33a
commit 7a523990a6
12 changed files with 763 additions and 9 deletions

View File

@ -17,13 +17,15 @@
import sys import sys
import os import os
from .builtin import Builtin
from .vpcs import VPCS from .vpcs import VPCS
from .virtualbox import VirtualBox from .virtualbox import VirtualBox
from .dynamips import Dynamips from .dynamips import Dynamips
from .qemu import Qemu from .qemu import Qemu
from .vmware import VMware from .vmware import VMware
MODULES = [VPCS, VirtualBox, Dynamips, Qemu, VMware] MODULES = [Builtin, VPCS, VirtualBox, Dynamips, Qemu, VMware]
if sys.platform.startswith("linux") or hasattr(sys, "_called_from_test") or os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1": if sys.platform.startswith("linux") or hasattr(sys, "_called_from_test") or os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1":

View File

@ -0,0 +1,36 @@
# -*- 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 <http://www.gnu.org/licenses/>.
"""
Builtin nodes server module.
"""
from ..base_manager import BaseManager
from .builtin_node_factory import BuiltinNodeFactory
import logging
log = logging.getLogger(__name__)
class Builtin(BaseManager):
_NODE_CLASS = BuiltinNodeFactory
def __init__(self):
super().__init__()

View File

@ -0,0 +1,39 @@
# -*- 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 <http://www.gnu.org/licenses/>.
from ..node_error import NodeError
from .nodes.ethernet_hub import EthernetHub
import logging
log = logging.getLogger(__name__)
BUILTIN_NODES = {'ethernet_hub': EthernetHub}
class BuiltinNodeFactory:
"""
Factory to create an builtin object based on the node type.
"""
def __new__(cls, name, node_id, project, manager, node_type, **kwargs):
if node_type not in BUILTIN_NODES:
raise NodeError("Unknown node type: {}".format(node_type))
return BUILTIN_NODES[node_type](name, node_id, project, manager, **kwargs)

View File

@ -0,0 +1,177 @@
# -*- 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 <http://www.gnu.org/licenses/>.
"""
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 EthernetHub(BaseNode):
"""
Ethernet hub
:param name: name for this hub
: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)
self._mappings = {}
def __json__(self):
return {"name": self.name,
"project_id": self.project.id,
"node_id": self.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))

View File

@ -42,7 +42,7 @@ from ..port_manager import PortManager
from .dynamips_error import DynamipsError from .dynamips_error import DynamipsError
from .hypervisor import Hypervisor from .hypervisor import Hypervisor
from .nodes.router import Router from .nodes.router import Router
from .dynamips_vm import DynamipsVM from .dynamips_vm_factory import DynamipsVMFactory
from .dynamips_device import DynamipsDevice from .dynamips_device import DynamipsDevice
# NIOs # NIOs
@ -102,7 +102,7 @@ WIC_MATRIX = {"WIC-1ENET": WIC_1ENET,
class Dynamips(BaseManager): class Dynamips(BaseManager):
_NODE_CLASS = DynamipsVM _NODE_CLASS = DynamipsVMFactory
_DEVICE_CLASS = DynamipsDevice _DEVICE_CLASS = DynamipsDevice
_ghost_ios_lock = None _ghost_ios_lock = None
@ -121,7 +121,6 @@ class Dynamips(BaseManager):
:returns: a free dynamips id :returns: a free dynamips id
""" """
self._dynamips_ids.setdefault(project_id, set()) self._dynamips_ids.setdefault(project_id, set())
dynamips_id = 0
for dynamips_id in range(1, 4097): for dynamips_id in range(1, 4097):
if dynamips_id not in self._dynamips_ids[project_id]: if dynamips_id not in self._dynamips_ids[project_id]:
self._dynamips_ids[project_id].add(dynamips_id) self._dynamips_ids[project_id].add(dynamips_id)

View File

@ -37,7 +37,7 @@ PLATFORMS = {'c1700': C1700,
'c7200': C7200} 'c7200': C7200}
class DynamipsVM: class DynamipsVMFactory:
""" """
Factory to create an Router object based on the correct platform. Factory to create an Router object based on the correct platform.

View File

@ -152,8 +152,9 @@ class Node:
""" """
data = copy.copy(self._properties) data = copy.copy(self._properties)
data["name"] = self._name data["name"] = self._name
data["console"] = self._console if self._console:
data["console_type"] = self._console_type data["console"] = self._console
data["console_type"] = self._console_type
# None properties should be send. Because it can mean the emulator doesn't support it # None properties should be send. Because it can mean the emulator doesn't support it
for key in list(data.keys()): for key in list(data.keys()):

View File

@ -29,7 +29,7 @@ from .vmware_handler import VMwareHandler
from .config_handler import ConfigHandler from .config_handler import ConfigHandler
from .version_handler import VersionHandler from .version_handler import VersionHandler
from .notification_handler import NotificationHandler from .notification_handler import NotificationHandler
from .ethernet_hub_handler import EthernetHubHandler
if sys.platform.startswith("linux") or hasattr(sys, "_called_from_test") or os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1": 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 testsuite work on UNIX platform

View File

@ -0,0 +1,226 @@
# -*- 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 <http://www.gnu.org/licenses/>.
import os
from gns3server.web.route import Route
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
from gns3server.compute.builtin import Builtin
from gns3server.schemas.ethernet_hub import (
ETHERNET_HUB_CREATE_SCHEMA,
ETHERNET_HUB_UPDATE_SCHEMA,
ETHERNET_HUB_OBJECT_SCHEMA,
ETHERNET_HUB_NIO_SCHEMA
)
class EthernetHubHandler:
"""
API entry points for Ethernet hub.
"""
@Route.post(
r"/projects/{project_id}/ethernet_hub/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new Ethernet hub instance",
input=ETHERNET_HUB_CREATE_SCHEMA,
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")
response.set_status(201)
response.json(node)
@Route.get(
r"/projects/{project_id}/ethernet_hub/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 hub instance",
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"])
response.json(node)
@Route.put(
r"/projects/{project_id}/ethernet_hub/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 hub instance",
input=ETHERNET_HUB_UPDATE_SCHEMA,
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)
response.json(node)
@Route.delete(
r"/projects/{project_id}/ethernet_hub/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 hub instance")
def delete(request, response):
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",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"port_number": "Port on the hub"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to an Ethernet hub instance",
input=ETHERNET_HUB_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"])
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)
response.set_status(201)
response.json(nio)
@Route.delete(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"port_number": "Port on the hub"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
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"])
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",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"port_number": "Port on the hub"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a packet capture on an Ethernet hub instance",
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"])
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",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"port_number": "Port on the hub"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
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"])
port_number = int(request.match_info["port_number"])
yield from node.stop_capture(port_number)
response.set_status(204)

View File

@ -0,0 +1,274 @@
# -*- 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 <http://www.gnu.org/licenses/>.
ETHERNET_HUB_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new Ethernet hub instance",
"type": "object",
"properties": {
"name": {
"description": "Ethernet hub name",
"type": "string",
"minLength": 1,
},
"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}$"}
]
}
},
"additionalProperties": False,
"required": ["name"]
}
ETHERNET_HUB_UPDATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Ethernet hub instance",
"type": "object",
"properties": {
"name": {
"description": "Ethernet hub name",
"type": "string",
"minLength": 1,
},
"ports": {
"description": "Number of ports",
"type": "integer"
}
},
"additionalProperties": False,
}
ETHERNET_HUB_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Ethernet hub instance",
"type": "object",
"properties": {
"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}$"
},
"name": {
"description": "Ethernet hub name",
"type": "string",
"minLength": 1,
},
"ports": {
"description": "Number of ports",
"type": "integer"
}
},
"additionalProperties": False,
"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"]
}

View File

@ -88,7 +88,7 @@ NODE_OBJECT_SCHEMA = {
}, },
"node_type": { "node_type": {
"description": "Type of node", "description": "Type of node",
"enum": ["docker", "dynamips", "vpcs", "virtualbox", "vmware", "iou", "qemu"] "enum": ["ethernet_hub", "docker", "dynamips", "vpcs", "virtualbox", "vmware", "iou", "qemu"]
}, },
"node_directory": { "node_directory": {
"description": "Working directory of the node. Read only", "description": "Working directory of the node. Read only",