mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-12 19:38:57 +00:00
New Dynamips integration part 1
This commit is contained in:
parent
648850c411
commit
46cbcd6132
@ -1 +1,6 @@
|
||||
__all__ = ['version_handler', 'network_handler', 'vpcs_handler', 'project_handler', 'virtualbox_handler']
|
||||
__all__ = ["version_handler",
|
||||
"network_handler",
|
||||
"vpcs_handler",
|
||||
"project_handler",
|
||||
"virtualbox_handler",
|
||||
"dynamips_handler"]
|
||||
|
58
gns3server/handlers/dynamips_handler.py
Normal file
58
gns3server/handlers/dynamips_handler.py
Normal file
@ -0,0 +1,58 @@
|
||||
# -*- 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 ..web.route import Route
|
||||
from ..schemas.dynamips import ROUTER_CREATE_SCHEMA
|
||||
from ..schemas.dynamips import ROUTER_OBJECT_SCHEMA
|
||||
from ..modules.dynamips import Dynamips
|
||||
from ..modules.project_manager import ProjectManager
|
||||
|
||||
|
||||
class DynamipsHandler:
|
||||
|
||||
"""
|
||||
API entry points for Dynamips.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/routers",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
400: "Invalid request",
|
||||
409: "Conflict"
|
||||
},
|
||||
description="Create a new Dynamips router instance",
|
||||
input=ROUTER_CREATE_SCHEMA)
|
||||
#output=ROUTER_OBJECT_SCHEMA)
|
||||
def create(request, response):
|
||||
|
||||
dynamips_manager = Dynamips.instance()
|
||||
vm = yield from dynamips_manager.create_vm(request.json.pop("name"),
|
||||
request.match_info["project_id"],
|
||||
request.json.get("vm_id"))
|
||||
|
||||
#for name, value in request.json.items():
|
||||
# if hasattr(vm, name) and getattr(vm, name) != value:
|
||||
# setattr(vm, name, value)
|
||||
|
||||
response.set_status(201)
|
||||
response.json(vm)
|
@ -15,8 +15,8 @@
|
||||
# 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 sys
|
||||
from .vpcs import VPCS
|
||||
from .virtualbox import VirtualBox
|
||||
from .dynamips import Dynamips
|
||||
|
||||
MODULES = [VPCS, VirtualBox]
|
||||
MODULES = [VPCS, VirtualBox, Dynamips]
|
||||
|
611
gns3server/modules/dynamips/__init__.py
Normal file
611
gns3server/modules/dynamips/__init__.py
Normal file
@ -0,0 +1,611 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Dynamips server module.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import base64
|
||||
import tempfile
|
||||
import shutil
|
||||
import glob
|
||||
import socket
|
||||
from gns3server.config import Config
|
||||
|
||||
# from .hypervisor import Hypervisor
|
||||
# from .hypervisor_manager import HypervisorManager
|
||||
# from .dynamips_error import DynamipsError
|
||||
#
|
||||
# # Nodes
|
||||
# from .nodes.router import Router
|
||||
# from .nodes.c1700 import C1700
|
||||
# from .nodes.c2600 import C2600
|
||||
# from .nodes.c2691 import C2691
|
||||
# from .nodes.c3600 import C3600
|
||||
# from .nodes.c3725 import C3725
|
||||
# from .nodes.c3745 import C3745
|
||||
# from .nodes.c7200 import C7200
|
||||
# from .nodes.bridge import Bridge
|
||||
# from .nodes.ethernet_switch import EthernetSwitch
|
||||
# from .nodes.atm_switch import ATMSwitch
|
||||
# from .nodes.atm_bridge import ATMBridge
|
||||
# from .nodes.frame_relay_switch import FrameRelaySwitch
|
||||
# from .nodes.hub import Hub
|
||||
#
|
||||
# # Adapters
|
||||
# from .adapters.c7200_io_2fe import C7200_IO_2FE
|
||||
# from .adapters.c7200_io_fe import C7200_IO_FE
|
||||
# from .adapters.c7200_io_ge_e import C7200_IO_GE_E
|
||||
# from .adapters.nm_16esw import NM_16ESW
|
||||
# from .adapters.nm_1e import NM_1E
|
||||
# from .adapters.nm_1fe_tx import NM_1FE_TX
|
||||
# from .adapters.nm_4e import NM_4E
|
||||
# from .adapters.nm_4t import NM_4T
|
||||
# from .adapters.pa_2fe_tx import PA_2FE_TX
|
||||
# from .adapters.pa_4e import PA_4E
|
||||
# from .adapters.pa_4t import PA_4T
|
||||
# from .adapters.pa_8e import PA_8E
|
||||
# from .adapters.pa_8t import PA_8T
|
||||
# from .adapters.pa_a1 import PA_A1
|
||||
# from .adapters.pa_fe_tx import PA_FE_TX
|
||||
# from .adapters.pa_ge import PA_GE
|
||||
# from .adapters.pa_pos_oc3 import PA_POS_OC3
|
||||
# from .adapters.wic_1t import WIC_1T
|
||||
# from .adapters.wic_2t import WIC_2T
|
||||
# from .adapters.wic_1enet import WIC_1ENET
|
||||
#
|
||||
# # NIOs
|
||||
# from .nios.nio_udp import NIO_UDP
|
||||
# from .nios.nio_udp_auto import NIO_UDP_auto
|
||||
# from .nios.nio_unix import NIO_UNIX
|
||||
# from .nios.nio_vde import NIO_VDE
|
||||
# from .nios.nio_tap import NIO_TAP
|
||||
# from .nios.nio_generic_ethernet import NIO_GenericEthernet
|
||||
# from .nios.nio_linux_ethernet import NIO_LinuxEthernet
|
||||
# from .nios.nio_fifo import NIO_FIFO
|
||||
# from .nios.nio_mcast import NIO_Mcast
|
||||
# from .nios.nio_null import NIO_Null
|
||||
#
|
||||
# from .backends import vm
|
||||
# from .backends import ethsw
|
||||
# from .backends import ethhub
|
||||
# from .backends import frsw
|
||||
# from .backends import atmsw
|
||||
|
||||
import time
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
from pkg_resources import parse_version
|
||||
from ..base_manager import BaseManager
|
||||
from .dynamips_error import DynamipsError
|
||||
from .hypervisor import Hypervisor
|
||||
from .nodes.router import Router
|
||||
|
||||
|
||||
class Dynamips(BaseManager):
|
||||
|
||||
_VM_CLASS = Router
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super().__init__()
|
||||
self._dynamips_path = None
|
||||
|
||||
# FIXME: temporary
|
||||
self._working_dir = "/tmp"
|
||||
self._dynamips_path = "/usr/local/bin/dynamips"
|
||||
|
||||
def find_dynamips(self):
|
||||
|
||||
# look for Dynamips
|
||||
dynamips_path = self.config.get_section_config("Dynamips").get("dynamips_path")
|
||||
if not dynamips_path:
|
||||
dynamips_path = shutil.which("dynamips")
|
||||
|
||||
if not dynamips_path:
|
||||
raise DynamipsError("Could not find Dynamips")
|
||||
if not os.path.isfile(dynamips_path):
|
||||
raise DynamipsError("Dynamips {} is not accessible".format(dynamips_path))
|
||||
if not os.access(dynamips_path, os.X_OK):
|
||||
raise DynamipsError("Dynamips is not executable")
|
||||
|
||||
self._dynamips_path = dynamips_path
|
||||
return dynamips_path
|
||||
|
||||
@asyncio.coroutine
|
||||
def _wait_for_hypervisor(self, host, port, timeout=10.0):
|
||||
"""
|
||||
Waits for an hypervisor to be started (accepting a socket connection)
|
||||
|
||||
:param host: host/address to connect to the hypervisor
|
||||
:param port: port to connect to the hypervisor
|
||||
"""
|
||||
|
||||
begin = time.time()
|
||||
connection_success = False
|
||||
last_exception = None
|
||||
while time.time() - begin < timeout:
|
||||
yield from asyncio.sleep(0.01)
|
||||
try:
|
||||
_, writer = yield from asyncio.open_connection(host, port)
|
||||
writer.close()
|
||||
except OSError as e:
|
||||
last_exception = e
|
||||
continue
|
||||
connection_success = True
|
||||
break
|
||||
|
||||
if not connection_success:
|
||||
raise DynamipsError("Couldn't connect to hypervisor on {}:{} :{}".format(host, port, last_exception))
|
||||
else:
|
||||
log.info("Dynamips server ready after {:.4f} seconds".format(time.time() - begin))
|
||||
|
||||
@asyncio.coroutine
|
||||
def start_new_hypervisor(self):
|
||||
"""
|
||||
Creates a new Dynamips process and start it.
|
||||
|
||||
:returns: the new hypervisor instance
|
||||
"""
|
||||
|
||||
try:
|
||||
# let the OS find an unused port for the Dynamips hypervisor
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
port = sock.getsockname()[1]
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not find free port for the Dynamips hypervisor: {}".format(e))
|
||||
|
||||
hypervisor = Hypervisor(self._dynamips_path, self._working_dir, "127.0.0.1", port)
|
||||
|
||||
log.info("Ceating new hypervisor {}:{} with working directory {}".format(hypervisor.host, hypervisor.port, self._working_dir))
|
||||
yield from hypervisor.start()
|
||||
|
||||
yield from self._wait_for_hypervisor("127.0.0.1", port)
|
||||
log.info("Hypervisor {}:{} has successfully started".format(hypervisor.host, hypervisor.port))
|
||||
|
||||
yield from hypervisor.connect()
|
||||
if parse_version(hypervisor.version) < parse_version('0.2.11'):
|
||||
raise DynamipsError("Dynamips version must be >= 0.2.11, detected version is {}".format(hypervisor.version))
|
||||
|
||||
return hypervisor
|
||||
|
||||
|
||||
# class Dynamips(IModule):
|
||||
# """
|
||||
# Dynamips module.
|
||||
#
|
||||
# :param name: module name
|
||||
# :param args: arguments for the module
|
||||
# :param kwargs: named arguments for the module
|
||||
# """
|
||||
#
|
||||
# def stop(self, signum=None):
|
||||
# """
|
||||
# Properly stops the module.
|
||||
#
|
||||
# :param signum: signal number (if called by the signal handler)
|
||||
# """
|
||||
#
|
||||
# if not sys.platform.startswith("win32"):
|
||||
# self._callback.stop()
|
||||
#
|
||||
# # automatically save configs for all router instances
|
||||
# for router_id in self._routers:
|
||||
# router = self._routers[router_id]
|
||||
# try:
|
||||
# router.save_configs()
|
||||
# except DynamipsError:
|
||||
# continue
|
||||
#
|
||||
# # stop all Dynamips hypervisors
|
||||
# if self._hypervisor_manager:
|
||||
# self._hypervisor_manager.stop_all_hypervisors()
|
||||
#
|
||||
# self.delete_dynamips_files()
|
||||
# IModule.stop(self, signum) # this will stop the I/O loop
|
||||
#
|
||||
# def get_device_instance(self, device_id, instance_dict):
|
||||
# """
|
||||
# Returns a device instance.
|
||||
#
|
||||
# :param device_id: device identifier
|
||||
# :param instance_dict: dictionary containing the instances
|
||||
#
|
||||
# :returns: device instance
|
||||
# """
|
||||
#
|
||||
# if device_id not in instance_dict:
|
||||
# log.debug("device ID {} doesn't exist".format(device_id), exc_info=1)
|
||||
# self.send_custom_error("Device ID {} doesn't exist".format(device_id))
|
||||
# return None
|
||||
# return instance_dict[device_id]
|
||||
#
|
||||
# def delete_dynamips_files(self):
|
||||
# """
|
||||
# Deletes useless Dynamips files from the working directory
|
||||
# """
|
||||
#
|
||||
# files = glob.glob(os.path.join(self._working_dir, "dynamips", "*.ghost"))
|
||||
# files += glob.glob(os.path.join(self._working_dir, "dynamips", "*_lock"))
|
||||
# files += glob.glob(os.path.join(self._working_dir, "dynamips", "ilt_*"))
|
||||
# files += glob.glob(os.path.join(self._working_dir, "dynamips", "c[0-9][0-9][0-9][0-9]_*_rommon_vars"))
|
||||
# files += glob.glob(os.path.join(self._working_dir, "dynamips", "c[0-9][0-9][0-9][0-9]_*_ssa"))
|
||||
# for file in files:
|
||||
# try:
|
||||
# log.debug("deleting file {}".format(file))
|
||||
# os.remove(file)
|
||||
# except OSError as e:
|
||||
# log.warn("could not delete file {}: {}".format(file, e))
|
||||
# continue
|
||||
#
|
||||
# @IModule.route("dynamips.reset")
|
||||
# def reset(self, request=None):
|
||||
# """
|
||||
# Resets the module (JSON-RPC notification).
|
||||
#
|
||||
# :param request: JSON request (not used)
|
||||
# """
|
||||
#
|
||||
# # automatically save configs for all router instances
|
||||
# for router_id in self._routers:
|
||||
# router = self._routers[router_id]
|
||||
# try:
|
||||
# router.save_configs()
|
||||
# except DynamipsError:
|
||||
# continue
|
||||
#
|
||||
# # stop all Dynamips hypervisors
|
||||
# if self._hypervisor_manager:
|
||||
# self._hypervisor_manager.stop_all_hypervisors()
|
||||
#
|
||||
# # resets the instance counters
|
||||
# Router.reset()
|
||||
# EthernetSwitch.reset()
|
||||
# Hub.reset()
|
||||
# FrameRelaySwitch.reset()
|
||||
# ATMSwitch.reset()
|
||||
# NIO_UDP.reset()
|
||||
# NIO_UDP_auto.reset()
|
||||
# NIO_UNIX.reset()
|
||||
# NIO_VDE.reset()
|
||||
# NIO_TAP.reset()
|
||||
# NIO_GenericEthernet.reset()
|
||||
# NIO_LinuxEthernet.reset()
|
||||
# NIO_FIFO.reset()
|
||||
# NIO_Mcast.reset()
|
||||
# NIO_Null.reset()
|
||||
#
|
||||
# self._routers.clear()
|
||||
# self._ethernet_switches.clear()
|
||||
# self._frame_relay_switches.clear()
|
||||
# self._atm_switches.clear()
|
||||
#
|
||||
# self.delete_dynamips_files()
|
||||
#
|
||||
# self._hypervisor_manager = None
|
||||
# self._working_dir = self._projects_dir
|
||||
# log.info("dynamips module has been reset")
|
||||
#
|
||||
# def start_hypervisor_manager(self):
|
||||
# """
|
||||
# Starts the hypervisor manager.
|
||||
# """
|
||||
#
|
||||
# # check if Dynamips path exists
|
||||
# if not os.path.isfile(self._dynamips):
|
||||
# raise DynamipsError("Dynamips executable {} doesn't exist".format(self._dynamips))
|
||||
#
|
||||
# # check if Dynamips is executable
|
||||
# if not os.access(self._dynamips, os.X_OK):
|
||||
# raise DynamipsError("Dynamips {} is not executable".format(self._dynamips))
|
||||
#
|
||||
# workdir = os.path.join(self._working_dir, "dynamips")
|
||||
# try:
|
||||
# os.makedirs(workdir)
|
||||
# except FileExistsError:
|
||||
# pass
|
||||
# except OSError as e:
|
||||
# raise DynamipsError("Could not create working directory {}".format(e))
|
||||
#
|
||||
# # check if the working directory is writable
|
||||
# if not os.access(workdir, os.W_OK):
|
||||
# raise DynamipsError("Cannot write to working directory {}".format(workdir))
|
||||
#
|
||||
# log.info("starting the hypervisor manager with Dynamips working directory set to '{}'".format(workdir))
|
||||
# self._hypervisor_manager = HypervisorManager(self._dynamips, workdir, self._host, self._console_host)
|
||||
#
|
||||
# for name, value in self._hypervisor_manager_settings.items():
|
||||
# if hasattr(self._hypervisor_manager, name) and getattr(self._hypervisor_manager, name) != value:
|
||||
# setattr(self._hypervisor_manager, name, value)
|
||||
#
|
||||
# @IModule.route("dynamips.settings")
|
||||
# def settings(self, request):
|
||||
# """
|
||||
# Set or update settings.
|
||||
#
|
||||
# Optional request parameters:
|
||||
# - path (path to the Dynamips executable)
|
||||
# - working_dir (path to a working directory)
|
||||
# - project_name
|
||||
#
|
||||
# :param request: JSON request
|
||||
# """
|
||||
#
|
||||
# if request is None:
|
||||
# self.send_param_error()
|
||||
# return
|
||||
#
|
||||
# log.debug("received request {}".format(request))
|
||||
#
|
||||
# #TODO: JSON schema validation
|
||||
# if not self._hypervisor_manager:
|
||||
#
|
||||
# if "path" in request:
|
||||
# self._dynamips = request.pop("path")
|
||||
#
|
||||
# if "working_dir" in request:
|
||||
# self._working_dir = request.pop("working_dir")
|
||||
# log.info("this server is local")
|
||||
# else:
|
||||
# self._working_dir = os.path.join(self._projects_dir, request["project_name"])
|
||||
# log.info("this server is remote with working directory path to {}".format(self._working_dir))
|
||||
#
|
||||
# self._hypervisor_manager_settings = request
|
||||
#
|
||||
# else:
|
||||
# if "project_name" in request:
|
||||
# # for remote server
|
||||
# new_working_dir = os.path.join(self._projects_dir, request["project_name"])
|
||||
#
|
||||
# if self._projects_dir != self._working_dir != new_working_dir:
|
||||
#
|
||||
# # trick to avoid file locks by Dynamips on Windows
|
||||
# if sys.platform.startswith("win"):
|
||||
# self._hypervisor_manager.working_dir = tempfile.gettempdir()
|
||||
#
|
||||
# if not os.path.isdir(new_working_dir):
|
||||
# try:
|
||||
# self.delete_dynamips_files()
|
||||
# shutil.move(self._working_dir, new_working_dir)
|
||||
# except OSError as e:
|
||||
# log.error("could not move working directory from {} to {}: {}".format(self._working_dir,
|
||||
# new_working_dir,
|
||||
# e))
|
||||
# return
|
||||
#
|
||||
# elif "working_dir" in request:
|
||||
# # for local server
|
||||
# new_working_dir = request.pop("working_dir")
|
||||
#
|
||||
# try:
|
||||
# self._hypervisor_manager.working_dir = new_working_dir
|
||||
# except DynamipsError as e:
|
||||
# log.error("could not change working directory: {}".format(e))
|
||||
# return
|
||||
#
|
||||
# self._working_dir = new_working_dir
|
||||
#
|
||||
# # apply settings to the hypervisor manager
|
||||
# for name, value in request.items():
|
||||
# if hasattr(self._hypervisor_manager, name) and getattr(self._hypervisor_manager, name) != value:
|
||||
# setattr(self._hypervisor_manager, name, value)
|
||||
#
|
||||
# @IModule.route("dynamips.echo")
|
||||
# def echo(self, request):
|
||||
# """
|
||||
# Echo end point for testing purposes.
|
||||
#
|
||||
# :param request: JSON request
|
||||
# """
|
||||
#
|
||||
# if request is None:
|
||||
# self.send_param_error()
|
||||
# else:
|
||||
# log.debug("received request {}".format(request))
|
||||
# self.send_response(request)
|
||||
#
|
||||
# def create_nio(self, node, request):
|
||||
# """
|
||||
# Creates a new NIO.
|
||||
#
|
||||
# :param node: node requesting the NIO
|
||||
# :param request: the original request with the
|
||||
# necessary information to create the NIO
|
||||
#
|
||||
# :returns: a NIO object
|
||||
# """
|
||||
#
|
||||
# nio = None
|
||||
# if request["nio"]["type"] == "nio_udp":
|
||||
# lport = request["nio"]["lport"]
|
||||
# rhost = request["nio"]["rhost"]
|
||||
# rport = request["nio"]["rport"]
|
||||
# try:
|
||||
# #TODO: handle IPv6
|
||||
# with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
||||
# sock.connect((rhost, rport))
|
||||
# except OSError as e:
|
||||
# raise DynamipsError("Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e))
|
||||
# # check if we have an allocated NIO UDP auto
|
||||
# nio = node.hypervisor.get_nio_udp_auto(lport)
|
||||
# if not nio:
|
||||
# # otherwise create an NIO UDP
|
||||
# nio = NIO_UDP(node.hypervisor, lport, rhost, rport)
|
||||
# else:
|
||||
# nio.connect(rhost, rport)
|
||||
# elif request["nio"]["type"] == "nio_generic_ethernet":
|
||||
# ethernet_device = request["nio"]["ethernet_device"]
|
||||
# if sys.platform.startswith("win"):
|
||||
# # replace the interface name by the GUID on Windows
|
||||
# interfaces = get_windows_interfaces()
|
||||
# npf_interface = None
|
||||
# for interface in interfaces:
|
||||
# if interface["name"] == ethernet_device:
|
||||
# npf_interface = interface["id"]
|
||||
# if not npf_interface:
|
||||
# raise DynamipsError("Could not find interface {} on this host".format(ethernet_device))
|
||||
# else:
|
||||
# ethernet_device = npf_interface
|
||||
# nio = NIO_GenericEthernet(node.hypervisor, ethernet_device)
|
||||
# elif request["nio"]["type"] == "nio_linux_ethernet":
|
||||
# if sys.platform.startswith("win"):
|
||||
# raise DynamipsError("This NIO type is not supported on Windows")
|
||||
# ethernet_device = request["nio"]["ethernet_device"]
|
||||
# nio = NIO_LinuxEthernet(node.hypervisor, ethernet_device)
|
||||
# elif request["nio"]["type"] == "nio_tap":
|
||||
# tap_device = request["nio"]["tap_device"]
|
||||
# nio = NIO_TAP(node.hypervisor, tap_device)
|
||||
# elif request["nio"]["type"] == "nio_unix":
|
||||
# local_file = request["nio"]["local_file"]
|
||||
# remote_file = request["nio"]["remote_file"]
|
||||
# nio = NIO_UNIX(node.hypervisor, local_file, remote_file)
|
||||
# elif request["nio"]["type"] == "nio_vde":
|
||||
# control_file = request["nio"]["control_file"]
|
||||
# local_file = request["nio"]["local_file"]
|
||||
# nio = NIO_VDE(node.hypervisor, control_file, local_file)
|
||||
# elif request["nio"]["type"] == "nio_null":
|
||||
# nio = NIO_Null(node.hypervisor)
|
||||
# return nio
|
||||
#
|
||||
# def allocate_udp_port(self, node):
|
||||
# """
|
||||
# Allocates a UDP port in order to create an UDP NIO.
|
||||
#
|
||||
# :param node: the node that needs to allocate an UDP port
|
||||
#
|
||||
# :returns: dictionary with the allocated host/port info
|
||||
# """
|
||||
#
|
||||
# port = node.hypervisor.allocate_udp_port()
|
||||
# host = node.hypervisor.host
|
||||
#
|
||||
# log.info("{} [id={}] has allocated UDP port {} with host {}".format(node.name,
|
||||
# node.id,
|
||||
# port,
|
||||
# host))
|
||||
# response = {"lport": port}
|
||||
# return response
|
||||
#
|
||||
# def set_ghost_ios(self, router):
|
||||
# """
|
||||
# Manages Ghost IOS support.
|
||||
#
|
||||
# :param router: Router instance
|
||||
# """
|
||||
#
|
||||
# if not router.mmap:
|
||||
# raise DynamipsError("mmap support is required to enable ghost IOS support")
|
||||
#
|
||||
# ghost_instance = router.formatted_ghost_file()
|
||||
# all_ghosts = []
|
||||
#
|
||||
# # search of an existing ghost instance across all hypervisors
|
||||
# for hypervisor in self._hypervisor_manager.hypervisors:
|
||||
# all_ghosts.extend(hypervisor.ghosts)
|
||||
#
|
||||
# if ghost_instance not in all_ghosts:
|
||||
# # create a new ghost IOS instance
|
||||
# ghost = Router(router.hypervisor, "ghost-" + ghost_instance, router.platform, ghost_flag=True)
|
||||
# ghost.image = router.image
|
||||
# # for 7200s, the NPE must be set when using an NPE-G2.
|
||||
# if router.platform == "c7200":
|
||||
# ghost.npe = router.npe
|
||||
# ghost.ghost_status = 1
|
||||
# ghost.ghost_file = ghost_instance
|
||||
# ghost.ram = router.ram
|
||||
# try:
|
||||
# ghost.start()
|
||||
# ghost.stop()
|
||||
# except DynamipsError:
|
||||
# raise
|
||||
# finally:
|
||||
# ghost.clean_delete()
|
||||
#
|
||||
# if router.ghost_file != ghost_instance:
|
||||
# # set the ghost file to the router
|
||||
# router.ghost_status = 2
|
||||
# router.ghost_file = ghost_instance
|
||||
#
|
||||
# def create_config_from_file(self, local_base_config, router, destination_config_path):
|
||||
# """
|
||||
# Creates a config file from a local base config
|
||||
#
|
||||
# :param local_base_config: path the a local base config
|
||||
# :param router: router instance
|
||||
# :param destination_config_path: path to the destination config file
|
||||
#
|
||||
# :returns: relative path to the created config file
|
||||
# """
|
||||
#
|
||||
# log.info("creating config file {} from {}".format(destination_config_path, local_base_config))
|
||||
# config_path = destination_config_path
|
||||
# config_dir = os.path.dirname(destination_config_path)
|
||||
# try:
|
||||
# os.makedirs(config_dir)
|
||||
# except FileExistsError:
|
||||
# pass
|
||||
# except OSError as e:
|
||||
# raise DynamipsError("Could not create configs directory: {}".format(e))
|
||||
#
|
||||
# try:
|
||||
# with open(local_base_config, "r", errors="replace") as f:
|
||||
# config = f.read()
|
||||
# with open(config_path, "w") as f:
|
||||
# config = "!\n" + config.replace("\r", "")
|
||||
# config = config.replace('%h', router.name)
|
||||
# f.write(config)
|
||||
# except OSError as e:
|
||||
# raise DynamipsError("Could not save the configuration from {} to {}: {}".format(local_base_config, config_path, e))
|
||||
# return "configs" + os.sep + os.path.basename(config_path)
|
||||
#
|
||||
# def create_config_from_base64(self, config_base64, router, destination_config_path):
|
||||
# """
|
||||
# Creates a config file from a base64 encoded config.
|
||||
#
|
||||
# :param config_base64: base64 encoded config
|
||||
# :param router: router instance
|
||||
# :param destination_config_path: path to the destination config file
|
||||
#
|
||||
# :returns: relative path to the created config file
|
||||
# """
|
||||
#
|
||||
# log.info("creating config file {} from base64".format(destination_config_path))
|
||||
# config = base64.decodebytes(config_base64.encode("utf-8")).decode("utf-8")
|
||||
# config = "!\n" + config.replace("\r", "")
|
||||
# config = config.replace('%h', router.name)
|
||||
# config_dir = os.path.dirname(destination_config_path)
|
||||
# try:
|
||||
# os.makedirs(config_dir)
|
||||
# except FileExistsError:
|
||||
# pass
|
||||
# except OSError as e:
|
||||
# raise DynamipsError("Could not create configs directory: {}".format(e))
|
||||
#
|
||||
# config_path = destination_config_path
|
||||
# try:
|
||||
# with open(config_path, "w") as f:
|
||||
# log.info("saving startup-config to {}".format(config_path))
|
||||
# f.write(config)
|
||||
# except OSError as e:
|
||||
# raise DynamipsError("Could not save the configuration {}: {}".format(config_path, e))
|
||||
# return "configs" + os.sep + os.path.basename(config_path)
|
@ -17,7 +17,6 @@
|
||||
|
||||
|
||||
class Adapter(object):
|
||||
|
||||
"""
|
||||
Base class for adapters.
|
||||
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class C1700_MB_1FE(Adapter):
|
||||
|
||||
"""
|
||||
Integrated 1 port FastEthernet adapter for c1700 platform.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class C1700_MB_WIC1(Adapter):
|
||||
|
||||
"""
|
||||
Fake module to provide a placeholder for slot 1 interfaces when WICs
|
||||
are inserted into WIC slot 1.
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class C2600_MB_1E(Adapter):
|
||||
|
||||
"""
|
||||
Integrated 1 port Ethernet adapter for the c2600 platform.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class C2600_MB_1FE(Adapter):
|
||||
|
||||
"""
|
||||
Integrated 1 port FastEthernet adapter for the c2600 platform.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class C2600_MB_2E(Adapter):
|
||||
|
||||
"""
|
||||
Integrated 2 port Ethernet adapter for the c2600 platform.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class C2600_MB_2FE(Adapter):
|
||||
|
||||
"""
|
||||
Integrated 2 port FastEthernet adapter for the c2600 platform.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class C7200_IO_2FE(Adapter):
|
||||
|
||||
"""
|
||||
C7200-IO-2FE FastEthernet Input/Ouput controller.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class C7200_IO_FE(Adapter):
|
||||
|
||||
"""
|
||||
C7200-IO-FE FastEthernet Input/Ouput controller.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class C7200_IO_GE_E(Adapter):
|
||||
|
||||
"""
|
||||
C7200-IO-GE-E GigabitEthernet Input/Ouput controller.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class Leopard_2FE(Adapter):
|
||||
|
||||
"""
|
||||
Integrated 2 port FastEthernet adapter for c3660 router.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class NM_16ESW(Adapter):
|
||||
|
||||
"""
|
||||
NM-16ESW FastEthernet network module.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class NM_1E(Adapter):
|
||||
|
||||
"""
|
||||
NM-1E Ethernet network module.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class NM_1FE_TX(Adapter):
|
||||
|
||||
"""
|
||||
NM-1FE-TX FastEthernet network module.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class NM_4E(Adapter):
|
||||
|
||||
"""
|
||||
NM-4E Ethernet network module.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class NM_4T(Adapter):
|
||||
|
||||
"""
|
||||
NM-4T Serial network module.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class PA_2FE_TX(Adapter):
|
||||
|
||||
"""
|
||||
PA-2FE-TX FastEthernet port adapter.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class PA_4E(Adapter):
|
||||
|
||||
"""
|
||||
PA-4E Ethernet port adapter.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class PA_4T(Adapter):
|
||||
|
||||
"""
|
||||
PA-4T+ Serial port adapter.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class PA_8E(Adapter):
|
||||
|
||||
"""
|
||||
PA-8E Ethernet port adapter.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class PA_8T(Adapter):
|
||||
|
||||
"""
|
||||
PA-8T Serial port adapter.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class PA_A1(Adapter):
|
||||
|
||||
"""
|
||||
PA-A1 ATM port adapter.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class PA_FE_TX(Adapter):
|
||||
|
||||
"""
|
||||
PA-FE-TX FastEthernet port adapter.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class PA_GE(Adapter):
|
||||
|
||||
"""
|
||||
PA-GE GigabitEthernet port adapter.
|
||||
"""
|
@ -19,7 +19,6 @@ from .adapter import Adapter
|
||||
|
||||
|
||||
class PA_POS_OC3(Adapter):
|
||||
|
||||
"""
|
||||
PA-POS-OC3 port adapter.
|
||||
"""
|
@ -17,7 +17,6 @@
|
||||
|
||||
|
||||
class WIC_1ENET(object):
|
||||
|
||||
"""
|
||||
WIC-1ENET Ethernet
|
||||
"""
|
@ -17,7 +17,6 @@
|
||||
|
||||
|
||||
class WIC_1T(object):
|
||||
|
||||
"""
|
||||
WIC-1T Serial
|
||||
"""
|
@ -17,7 +17,6 @@
|
||||
|
||||
|
||||
class WIC_2T(object):
|
||||
|
||||
"""
|
||||
WIC-2T Serial
|
||||
"""
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2013 GNS3 Technologies Inc.
|
||||
# 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
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2013 GNS3 Technologies Inc.
|
||||
# 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
|
||||
@ -23,14 +23,15 @@ http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L46
|
||||
import socket
|
||||
import re
|
||||
import logging
|
||||
import asyncio
|
||||
|
||||
from .dynamips_error import DynamipsError
|
||||
from .nios.nio_udp_auto import NIO_UDP_auto
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DynamipsHypervisor(object):
|
||||
|
||||
class DynamipsHypervisor:
|
||||
"""
|
||||
Creates a new connection to a Dynamips server (also called hypervisor)
|
||||
|
||||
@ -54,18 +55,20 @@ class DynamipsHypervisor(object):
|
||||
self._ghosts = {}
|
||||
self._jitsharing_groups = {}
|
||||
self._working_dir = working_dir
|
||||
self._console_start_port_range = 2001
|
||||
self._console_end_port_range = 2500
|
||||
self._aux_start_port_range = 2501
|
||||
self._aux_end_port_range = 3000
|
||||
self._udp_start_port_range = 10001
|
||||
self._udp_end_port_range = 20000
|
||||
# self._console_start_port_range = 2001
|
||||
# self._console_end_port_range = 2500
|
||||
# self._aux_start_port_range = 2501
|
||||
# self._aux_end_port_range = 3000
|
||||
# self._udp_start_port_range = 10001
|
||||
# self._udp_end_port_range = 20000
|
||||
self._nio_udp_auto_instances = {}
|
||||
self._version = "N/A"
|
||||
self._timeout = timeout
|
||||
self._socket = None
|
||||
self._uuid = None
|
||||
self._reader = None
|
||||
self._writer = None
|
||||
|
||||
@asyncio.coroutine
|
||||
def connect(self):
|
||||
"""
|
||||
Connects to the hypervisor.
|
||||
@ -81,19 +84,22 @@ class DynamipsHypervisor(object):
|
||||
host = self._host
|
||||
|
||||
try:
|
||||
self._socket = socket.create_connection((host, self._port), self._timeout)
|
||||
self._reader, self._writer = yield from asyncio.wait_for(asyncio.open_connection(host, self._port), timeout=self._timeout)
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not connect to server: {}".format(e))
|
||||
raise DynamipsError("Could not connect to hypervisor {}:{} {}".format(host, self._port, e))
|
||||
except asyncio.TimeoutError:
|
||||
raise DynamipsError("Timeout error while connecting to hypervisor {}:{}".format(host, self._port))
|
||||
|
||||
try:
|
||||
self._version = self.send("hypervisor version")[0].split("-", 1)[0]
|
||||
version = yield from self.send("hypervisor version")
|
||||
self._version = version[0].split("-", 1)[0]
|
||||
except IndexError:
|
||||
self._version = "Unknown"
|
||||
|
||||
self._uuid = self.send("hypervisor uuid")
|
||||
self._uuid = yield from self.send("hypervisor uuid")
|
||||
|
||||
# this forces to send the working dir to Dynamips
|
||||
self.working_dir = self._working_dir
|
||||
yield from self.set_working_dir(self._working_dir)
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
@ -105,54 +111,49 @@ class DynamipsHypervisor(object):
|
||||
|
||||
return self._version
|
||||
|
||||
def module_list(self):
|
||||
"""
|
||||
Returns the modules supported by this hypervisor.
|
||||
|
||||
:returns: module list
|
||||
"""
|
||||
|
||||
return self.send("hypervisor module_list")
|
||||
|
||||
def cmd_list(self, module):
|
||||
"""
|
||||
Returns commands recognized by the specified module.
|
||||
|
||||
:param module: the module name
|
||||
:returns: command list
|
||||
"""
|
||||
|
||||
return self.send("hypervisor cmd_list {}".format(module))
|
||||
|
||||
@asyncio.coroutine
|
||||
def close(self):
|
||||
"""
|
||||
Closes the connection to this hypervisor (but leave it running).
|
||||
"""
|
||||
|
||||
self.send("hypervisor close")
|
||||
self._socket.shutdown(socket.SHUT_RDWR)
|
||||
self._socket.close()
|
||||
self._socket = None
|
||||
yield from self.send("hypervisor close")
|
||||
self._writer.close()
|
||||
self._reader, self._writer = None
|
||||
|
||||
@asyncio.coroutine
|
||||
def stop(self):
|
||||
"""
|
||||
Stops this hypervisor (will no longer run).
|
||||
"""
|
||||
|
||||
self.send("hypervisor stop")
|
||||
self._socket.shutdown(socket.SHUT_RDWR)
|
||||
self._socket.close()
|
||||
self._socket = None
|
||||
yield from self.send("hypervisor stop")
|
||||
self._writer.close()
|
||||
self._reader, self._writer = None
|
||||
self._nio_udp_auto_instances.clear()
|
||||
|
||||
@asyncio.coroutine
|
||||
def reset(self):
|
||||
"""
|
||||
Resets this hypervisor (used to get an empty configuration).
|
||||
"""
|
||||
|
||||
self.send('hypervisor reset')
|
||||
yield from self.send("hypervisor reset")
|
||||
self._nio_udp_auto_instances.clear()
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_working_dir(self, working_dir):
|
||||
"""
|
||||
Sets the working directory for this hypervisor.
|
||||
|
||||
:param working_dir: path to the working directory
|
||||
"""
|
||||
|
||||
# encase working_dir in quotes to protect spaces in the path
|
||||
yield from self.send("hypervisor working_dir {}".format('"' + working_dir + '"'))
|
||||
self._working_dir = working_dir
|
||||
log.debug("Working directory set to {}".format(self._working_dir))
|
||||
|
||||
@property
|
||||
def working_dir(self):
|
||||
"""
|
||||
@ -163,29 +164,6 @@ class DynamipsHypervisor(object):
|
||||
|
||||
return self._working_dir
|
||||
|
||||
@working_dir.setter
|
||||
def working_dir(self, working_dir):
|
||||
"""
|
||||
Sets the working directory for this hypervisor.
|
||||
|
||||
:param working_dir: path to the working directory
|
||||
"""
|
||||
|
||||
# encase working_dir in quotes to protect spaces in the path
|
||||
self.send("hypervisor working_dir {}".format('"' + working_dir + '"'))
|
||||
self._working_dir = working_dir
|
||||
log.debug("working directory set to {}".format(self._working_dir))
|
||||
|
||||
def save_config(self, filename):
|
||||
"""
|
||||
Saves the configuration of all Dynamips instances into the specified file.
|
||||
|
||||
:param filename: path string
|
||||
"""
|
||||
|
||||
# encase working_dir in quotes to protect spaces in the path
|
||||
self.send("hypervisor save_config {}".format('"' + filename + '"'))
|
||||
|
||||
@property
|
||||
def uuid(self):
|
||||
"""
|
||||
@ -196,17 +174,6 @@ class DynamipsHypervisor(object):
|
||||
|
||||
return self._uuid
|
||||
|
||||
@property
|
||||
def socket(self):
|
||||
"""
|
||||
Returns the current socket used to communicate with this hypervisor.
|
||||
|
||||
:returns: socket instance
|
||||
"""
|
||||
|
||||
assert self._socket
|
||||
return self._socket
|
||||
|
||||
@property
|
||||
def devices(self):
|
||||
"""
|
||||
@ -217,136 +184,136 @@ class DynamipsHypervisor(object):
|
||||
|
||||
return self._devices
|
||||
|
||||
@devices.setter
|
||||
def devices(self, devices):
|
||||
"""
|
||||
Sets the list of devices managed by this hypervisor instance.
|
||||
This method is for internal use.
|
||||
# @devices.setter
|
||||
# def devices(self, devices):
|
||||
# """
|
||||
# Sets the list of devices managed by this hypervisor instance.
|
||||
# This method is for internal use.
|
||||
#
|
||||
# :param devices: a list of device objects
|
||||
# """
|
||||
#
|
||||
# self._devices = devices
|
||||
|
||||
:param devices: a list of device objects
|
||||
"""
|
||||
# @property
|
||||
# def console_start_port_range(self):
|
||||
# """
|
||||
# Returns the console start port range value
|
||||
#
|
||||
# :returns: console start port range value (integer)
|
||||
# """
|
||||
#
|
||||
# return self._console_start_port_range
|
||||
|
||||
self._devices = devices
|
||||
# @console_start_port_range.setter
|
||||
# def console_start_port_range(self, console_start_port_range):
|
||||
# """
|
||||
# Set a new console start port range value
|
||||
#
|
||||
# :param console_start_port_range: console start port range value (integer)
|
||||
# """
|
||||
#
|
||||
# self._console_start_port_range = console_start_port_range
|
||||
#
|
||||
# @property
|
||||
# def console_end_port_range(self):
|
||||
# """
|
||||
# Returns the console end port range value
|
||||
#
|
||||
# :returns: console end port range value (integer)
|
||||
# """
|
||||
#
|
||||
# return self._console_end_port_range
|
||||
#
|
||||
# @console_end_port_range.setter
|
||||
# def console_end_port_range(self, console_end_port_range):
|
||||
# """
|
||||
# Set a new console end port range value
|
||||
#
|
||||
# :param console_end_port_range: console end port range value (integer)
|
||||
# """
|
||||
#
|
||||
# self._console_end_port_range = console_end_port_range
|
||||
|
||||
@property
|
||||
def console_start_port_range(self):
|
||||
"""
|
||||
Returns the console start port range value
|
||||
# @property
|
||||
# def aux_start_port_range(self):
|
||||
# """
|
||||
# Returns the auxiliary console start port range value
|
||||
#
|
||||
# :returns: auxiliary console start port range value (integer)
|
||||
# """
|
||||
#
|
||||
# return self._aux_start_port_range
|
||||
#
|
||||
# @aux_start_port_range.setter
|
||||
# def aux_start_port_range(self, aux_start_port_range):
|
||||
# """
|
||||
# Sets a new auxiliary console start port range value
|
||||
#
|
||||
# :param aux_start_port_range: auxiliary console start port range value (integer)
|
||||
# """
|
||||
#
|
||||
# self._aux_start_port_range = aux_start_port_range
|
||||
#
|
||||
# @property
|
||||
# def aux_end_port_range(self):
|
||||
# """
|
||||
# Returns the auxiliary console end port range value
|
||||
#
|
||||
# :returns: auxiliary console end port range value (integer)
|
||||
# """
|
||||
#
|
||||
# return self._aux_end_port_range
|
||||
#
|
||||
# @aux_end_port_range.setter
|
||||
# def aux_end_port_range(self, aux_end_port_range):
|
||||
# """
|
||||
# Sets a new auxiliary console end port range value
|
||||
#
|
||||
# :param aux_end_port_range: auxiliary console end port range value (integer)
|
||||
# """
|
||||
#
|
||||
# self._aux_end_port_range = aux_end_port_range
|
||||
|
||||
:returns: console start port range value (integer)
|
||||
"""
|
||||
|
||||
return self._console_start_port_range
|
||||
|
||||
@console_start_port_range.setter
|
||||
def console_start_port_range(self, console_start_port_range):
|
||||
"""
|
||||
Set a new console start port range value
|
||||
|
||||
:param console_start_port_range: console start port range value (integer)
|
||||
"""
|
||||
|
||||
self._console_start_port_range = console_start_port_range
|
||||
|
||||
@property
|
||||
def console_end_port_range(self):
|
||||
"""
|
||||
Returns the console end port range value
|
||||
|
||||
:returns: console end port range value (integer)
|
||||
"""
|
||||
|
||||
return self._console_end_port_range
|
||||
|
||||
@console_end_port_range.setter
|
||||
def console_end_port_range(self, console_end_port_range):
|
||||
"""
|
||||
Set a new console end port range value
|
||||
|
||||
:param console_end_port_range: console end port range value (integer)
|
||||
"""
|
||||
|
||||
self._console_end_port_range = console_end_port_range
|
||||
|
||||
@property
|
||||
def aux_start_port_range(self):
|
||||
"""
|
||||
Returns the auxiliary console start port range value
|
||||
|
||||
:returns: auxiliary console start port range value (integer)
|
||||
"""
|
||||
|
||||
return self._aux_start_port_range
|
||||
|
||||
@aux_start_port_range.setter
|
||||
def aux_start_port_range(self, aux_start_port_range):
|
||||
"""
|
||||
Sets a new auxiliary console start port range value
|
||||
|
||||
:param aux_start_port_range: auxiliary console start port range value (integer)
|
||||
"""
|
||||
|
||||
self._aux_start_port_range = aux_start_port_range
|
||||
|
||||
@property
|
||||
def aux_end_port_range(self):
|
||||
"""
|
||||
Returns the auxiliary console end port range value
|
||||
|
||||
:returns: auxiliary console end port range value (integer)
|
||||
"""
|
||||
|
||||
return self._aux_end_port_range
|
||||
|
||||
@aux_end_port_range.setter
|
||||
def aux_end_port_range(self, aux_end_port_range):
|
||||
"""
|
||||
Sets a new auxiliary console end port range value
|
||||
|
||||
:param aux_end_port_range: auxiliary console end port range value (integer)
|
||||
"""
|
||||
|
||||
self._aux_end_port_range = aux_end_port_range
|
||||
|
||||
@property
|
||||
def udp_start_port_range(self):
|
||||
"""
|
||||
Returns the UDP start port range value
|
||||
|
||||
:returns: UDP start port range value (integer)
|
||||
"""
|
||||
|
||||
return self._udp_start_port_range
|
||||
|
||||
@udp_start_port_range.setter
|
||||
def udp_start_port_range(self, udp_start_port_range):
|
||||
"""
|
||||
Sets a new UDP start port range value
|
||||
|
||||
:param udp_start_port_range: UDP start port range value (integer)
|
||||
"""
|
||||
|
||||
self._udp_start_port_range = udp_start_port_range
|
||||
|
||||
@property
|
||||
def udp_end_port_range(self):
|
||||
"""
|
||||
Returns the UDP end port range value
|
||||
|
||||
:returns: UDP end port range value (integer)
|
||||
"""
|
||||
|
||||
return self._udp_end_port_range
|
||||
|
||||
@udp_end_port_range.setter
|
||||
def udp_end_port_range(self, udp_end_port_range):
|
||||
"""
|
||||
Sets an new UDP end port range value
|
||||
|
||||
:param udp_end_port_range: UDP end port range value (integer)
|
||||
"""
|
||||
|
||||
self._udp_end_port_range = udp_end_port_range
|
||||
# @property
|
||||
# def udp_start_port_range(self):
|
||||
# """
|
||||
# Returns the UDP start port range value
|
||||
#
|
||||
# :returns: UDP start port range value (integer)
|
||||
# """
|
||||
#
|
||||
# return self._udp_start_port_range
|
||||
#
|
||||
# @udp_start_port_range.setter
|
||||
# def udp_start_port_range(self, udp_start_port_range):
|
||||
# """
|
||||
# Sets a new UDP start port range value
|
||||
#
|
||||
# :param udp_start_port_range: UDP start port range value (integer)
|
||||
# """
|
||||
#
|
||||
# self._udp_start_port_range = udp_start_port_range
|
||||
#
|
||||
# @property
|
||||
# def udp_end_port_range(self):
|
||||
# """
|
||||
# Returns the UDP end port range value
|
||||
#
|
||||
# :returns: UDP end port range value (integer)
|
||||
# """
|
||||
#
|
||||
# return self._udp_end_port_range
|
||||
#
|
||||
# @udp_end_port_range.setter
|
||||
# def udp_end_port_range(self, udp_end_port_range):
|
||||
# """
|
||||
# Sets an new UDP end port range value
|
||||
#
|
||||
# :param udp_end_port_range: UDP end port range value (integer)
|
||||
# """
|
||||
#
|
||||
# self._udp_end_port_range = udp_end_port_range
|
||||
|
||||
@property
|
||||
def ghosts(self):
|
||||
@ -388,25 +355,45 @@ class DynamipsHypervisor(object):
|
||||
|
||||
self._jitsharing_groups[image_name] = group_number
|
||||
|
||||
@property
|
||||
def port(self):
|
||||
"""
|
||||
Returns the port used to start the hypervisor.
|
||||
|
||||
:returns: port number (integer)
|
||||
"""
|
||||
|
||||
return self._port
|
||||
|
||||
@port.setter
|
||||
def port(self, port):
|
||||
"""
|
||||
Sets the port used to start the hypervisor.
|
||||
|
||||
:param port: port number (integer)
|
||||
"""
|
||||
|
||||
self._port = port
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
"""
|
||||
Returns this hypervisor host.
|
||||
Returns the host (binding) used to start the hypervisor.
|
||||
|
||||
:returns: host (string)
|
||||
:returns: host/address (string)
|
||||
"""
|
||||
|
||||
return self._host
|
||||
|
||||
@property
|
||||
def port(self):
|
||||
@host.setter
|
||||
def host(self, host):
|
||||
"""
|
||||
Returns this hypervisor port.
|
||||
Sets the host (binding) used to start the hypervisor.
|
||||
|
||||
:returns: port (integer)
|
||||
:param host: host/address (string)
|
||||
"""
|
||||
|
||||
return self._port
|
||||
self._host = host
|
||||
|
||||
def get_nio_udp_auto(self, port):
|
||||
"""
|
||||
@ -433,18 +420,7 @@ class DynamipsHypervisor(object):
|
||||
allocated_port = nio.lport
|
||||
return allocated_port
|
||||
|
||||
def send_raw(self, string):
|
||||
"""
|
||||
Sends a raw command to this hypervisor. Use sparingly.
|
||||
|
||||
:param string: command string.
|
||||
|
||||
:returns: command result (string)
|
||||
"""
|
||||
|
||||
result = self.send(string)
|
||||
return result
|
||||
|
||||
@asyncio.coroutine
|
||||
def send(self, command):
|
||||
"""
|
||||
Sends commands to this hypervisor.
|
||||
@ -467,13 +443,13 @@ class DynamipsHypervisor(object):
|
||||
# but still have more data. The only thing we know for sure is the last line
|
||||
# will begin with '100-' or a '2xx-' and end with '\r\n'
|
||||
|
||||
if not self._socket:
|
||||
if self._writer is None or self._reader is None:
|
||||
raise DynamipsError("Not connected")
|
||||
|
||||
try:
|
||||
command = command.strip() + '\n'
|
||||
log.debug("sending {}".format(command))
|
||||
self.socket.sendall(command.encode('utf-8'))
|
||||
self._writer.write(command.encode())
|
||||
except OSError as e:
|
||||
raise DynamipsError("Lost communication with {host}:{port} :{error}, Dynamips process running: {run}"
|
||||
.format(host=self._host, port=self._port, error=e, run=self.is_running()))
|
||||
@ -483,8 +459,8 @@ class DynamipsHypervisor(object):
|
||||
buf = ''
|
||||
while True:
|
||||
try:
|
||||
chunk = self.socket.recv(1024) # match to Dynamips' buffer size
|
||||
buf += chunk.decode("utf-8")
|
||||
chunk = yield from self._reader.read(1024) # match to Dynamips' buffer size
|
||||
buf += chunk.decode()
|
||||
except OSError as e:
|
||||
raise DynamipsError("Communication timed out with {host}:{port} :{error}, Dynamips process running: {run}"
|
||||
.format(host=self._host, port=self._port, error=e, run=self.is_running()))
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2013 GNS3 Technologies Inc.
|
||||
# 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
|
||||
@ -20,9 +20,9 @@ Represents a Dynamips hypervisor and starts/stops the associated Dynamips proces
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import tempfile
|
||||
import asyncio
|
||||
|
||||
from .dynamips_hypervisor import DynamipsHypervisor
|
||||
from .dynamips_error import DynamipsError
|
||||
@ -32,7 +32,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Hypervisor(DynamipsHypervisor):
|
||||
|
||||
"""
|
||||
Hypervisor.
|
||||
|
||||
@ -58,11 +57,6 @@ class Hypervisor(DynamipsHypervisor):
|
||||
self._stdout_file = ""
|
||||
self._started = False
|
||||
|
||||
# settings used the load-balance hypervisors
|
||||
# (for the hypervisor manager)
|
||||
self._memory_load = 0
|
||||
self._ios_image_ref = ""
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
@ -103,99 +97,7 @@ class Hypervisor(DynamipsHypervisor):
|
||||
|
||||
self._path = path
|
||||
|
||||
@property
|
||||
def port(self):
|
||||
"""
|
||||
Returns the port used to start the Dynamips hypervisor.
|
||||
|
||||
:returns: port number (integer)
|
||||
"""
|
||||
|
||||
return self._port
|
||||
|
||||
@port.setter
|
||||
def port(self, port):
|
||||
"""
|
||||
Sets the port used to start the Dynamips hypervisor.
|
||||
|
||||
:param port: port number (integer)
|
||||
"""
|
||||
|
||||
self._port = port
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
"""
|
||||
Returns the host (binding) used to start the Dynamips hypervisor.
|
||||
|
||||
:returns: host/address (string)
|
||||
"""
|
||||
|
||||
return self._host
|
||||
|
||||
@host.setter
|
||||
def host(self, host):
|
||||
"""
|
||||
Sets the host (binding) used to start the Dynamips hypervisor.
|
||||
|
||||
:param host: host/address (string)
|
||||
"""
|
||||
|
||||
self._host = host
|
||||
|
||||
@property
|
||||
def image_ref(self):
|
||||
"""
|
||||
Returns the reference IOS image name
|
||||
(used by the hypervisor manager for load-balancing purposes).
|
||||
|
||||
:returns: image reference name
|
||||
"""
|
||||
|
||||
return self._ios_image_ref
|
||||
|
||||
@image_ref.setter
|
||||
def image_ref(self, ios_image_name):
|
||||
"""
|
||||
Sets the reference IOS image name
|
||||
(used by the hypervisor manager for load-balancing purposes).
|
||||
|
||||
:param ios_image_name: image reference name
|
||||
"""
|
||||
|
||||
self._ios_image_ref = ios_image_name
|
||||
|
||||
def increase_memory_load(self, memory):
|
||||
"""
|
||||
Increases the memory load of this hypervisor.
|
||||
(used by the hypervisor manager for load-balancing purposes).
|
||||
|
||||
:param memory: amount of RAM (integer)
|
||||
"""
|
||||
|
||||
self._memory_load += memory
|
||||
|
||||
def decrease_memory_load(self, memory):
|
||||
"""
|
||||
Decreases the memory load of this hypervisor.
|
||||
(used by the hypervisor manager for load-balancing purposes).
|
||||
|
||||
:param memory: amount of RAM (integer)
|
||||
"""
|
||||
|
||||
self._memory_load -= memory
|
||||
|
||||
@property
|
||||
def memory_load(self):
|
||||
"""
|
||||
Returns the memory load of this hypervisor.
|
||||
(used by the hypervisor manager for load-balancing purposes).
|
||||
|
||||
:returns: amount of RAM (integer)
|
||||
"""
|
||||
|
||||
return self._memory_load
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self):
|
||||
"""
|
||||
Starts the Dynamips hypervisor process.
|
||||
@ -203,37 +105,38 @@ class Hypervisor(DynamipsHypervisor):
|
||||
|
||||
self._command = self._build_command()
|
||||
try:
|
||||
log.info("starting Dynamips: {}".format(self._command))
|
||||
log.info("Starting Dynamips: {}".format(self._command))
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False) as fd:
|
||||
self._stdout_file = fd.name
|
||||
log.info("Dynamips process logging to {}".format(fd.name))
|
||||
self._process = subprocess.Popen(self._command,
|
||||
stdout=fd,
|
||||
stderr=subprocess.STDOUT,
|
||||
cwd=self._working_dir)
|
||||
log.info("Dynamips started PID={}".format(self._process.pid))
|
||||
self._process = yield from asyncio.create_subprocess_exec(*self._command,
|
||||
stdout=fd,
|
||||
stderr=subprocess.STDOUT,
|
||||
cwd=self._working_dir)
|
||||
log.info("Dynamips process started PID={}".format(self._process.pid))
|
||||
self._started = True
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
log.error("could not start Dynamips: {}".format(e))
|
||||
raise DynamipsError("could not start Dynamips: {}".format(e))
|
||||
log.error("Could not start Dynamips: {}".format(e))
|
||||
raise DynamipsError("Could not start Dynamips: {}".format(e))
|
||||
|
||||
@asyncio.coroutine
|
||||
def stop(self):
|
||||
"""
|
||||
Stops the Dynamips hypervisor process.
|
||||
"""
|
||||
|
||||
if self.is_running():
|
||||
log.info("Stopping Dynamips process PID={}".format(self._process.pid))
|
||||
DynamipsHypervisor.stop(self)
|
||||
log.info("stopping Dynamips PID={}".format(self._process.pid))
|
||||
# give some time for the hypervisor to properly stop.
|
||||
# time to delete UNIX NIOs for instance.
|
||||
yield from asyncio.sleep(0.01)
|
||||
try:
|
||||
# give some time for the hypervisor to properly stop.
|
||||
# time to delete UNIX NIOs for instance.
|
||||
time.sleep(0.01)
|
||||
self._process.terminate()
|
||||
self._process.wait(1)
|
||||
except subprocess.TimeoutExpired:
|
||||
yield from asyncio.wait_for(self._process.wait(), timeout=3)
|
||||
except asyncio.TimeoutError:
|
||||
self._process.kill()
|
||||
if self._process.poll() is None:
|
||||
if self._process.returncode is None:
|
||||
log.warn("Dynamips process {} is still running".format(self._process.pid))
|
||||
|
||||
if self._stdout_file and os.access(self._stdout_file, os.W_OK):
|
||||
@ -265,7 +168,7 @@ class Hypervisor(DynamipsHypervisor):
|
||||
:returns: True or False
|
||||
"""
|
||||
|
||||
if self._process and self._process.poll() is None:
|
||||
if self._process and self._process.returncode is None:
|
||||
return True
|
||||
return False
|
||||
|
@ -20,23 +20,24 @@ Base interface for Dynamips Network Input/Output (NIO) module ("nio").
|
||||
http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L451
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO(object):
|
||||
|
||||
class NIO:
|
||||
"""
|
||||
Base NIO class
|
||||
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor):
|
||||
def __init__(self, name, hypervisor):
|
||||
|
||||
self._hypervisor = hypervisor
|
||||
self._name = None
|
||||
self._bandwidth = None # no bandwidth constraint by default
|
||||
self._input_filter = None # no input filter applied by default
|
||||
self._output_filter = None # no output filter applied by default
|
||||
@ -44,6 +45,7 @@ class NIO(object):
|
||||
self._output_filter_options = None # no output filter options by default
|
||||
self._dynamips_direction = {"in": 0, "out": 1, "both": 2}
|
||||
|
||||
@asyncio.coroutine
|
||||
def list(self):
|
||||
"""
|
||||
Returns all NIOs.
|
||||
@ -51,18 +53,21 @@ class NIO(object):
|
||||
:returns: NIO list
|
||||
"""
|
||||
|
||||
return self._hypervisor.send("nio list")
|
||||
nio_list = yield from self._hypervisor.send("nio list")
|
||||
return nio_list
|
||||
|
||||
@asyncio.coroutine
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this NIO.
|
||||
"""
|
||||
|
||||
if self._input_filter or self._output_filter:
|
||||
self.unbind_filter("both")
|
||||
self._hypervisor.send("nio delete {}".format(self._name))
|
||||
yield from self.unbind_filter("both")
|
||||
yield from self._hypervisor.send("nio delete {}".format(self._name))
|
||||
log.info("NIO {name} has been deleted".format(name=self._name))
|
||||
|
||||
@asyncio.coroutine
|
||||
def rename(self, new_name):
|
||||
"""
|
||||
Renames this NIO
|
||||
@ -70,13 +75,12 @@ class NIO(object):
|
||||
:param new_name: new NIO name
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
yield from self._hypervisor.send("nio rename {name} {new_name}".format(name=self._name, new_name=new_name))
|
||||
|
||||
log.info("NIO {name} renamed to {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
log.info("NIO {name} renamed to {new_name}".format(name=self._name, new_name=new_name))
|
||||
self._name = new_name
|
||||
|
||||
@asyncio.coroutine
|
||||
def debug(self, debug):
|
||||
"""
|
||||
Enables/Disables debugging for this NIO.
|
||||
@ -84,9 +88,9 @@ class NIO(object):
|
||||
:param debug: debug value (0 = disable, enable = 1)
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio set_debug {name} {debug}".format(name=self._name,
|
||||
debug=debug))
|
||||
yield from self._hypervisor.send("nio set_debug {name} {debug}".format(name=self._name, debug=debug))
|
||||
|
||||
@asyncio.coroutine
|
||||
def bind_filter(self, direction, filter_name):
|
||||
"""
|
||||
Adds a packet filter to this NIO.
|
||||
@ -101,9 +105,9 @@ class NIO(object):
|
||||
raise DynamipsError("Unknown direction {} to bind filter {}:".format(direction, filter_name))
|
||||
dynamips_direction = self._dynamips_direction[direction]
|
||||
|
||||
self._hypervisor.send("nio bind_filter {name} {direction} {filter}".format(name=self._name,
|
||||
direction=dynamips_direction,
|
||||
filter=filter_name))
|
||||
yield from self._hypervisor.send("nio bind_filter {name} {direction} {filter}".format(name=self._name,
|
||||
direction=dynamips_direction,
|
||||
filter=filter_name))
|
||||
|
||||
if direction == "in":
|
||||
self._input_filter = filter_name
|
||||
@ -113,6 +117,7 @@ class NIO(object):
|
||||
self._input_filter = filter_name
|
||||
self._output_filter = filter_name
|
||||
|
||||
@asyncio.coroutine
|
||||
def unbind_filter(self, direction):
|
||||
"""
|
||||
Removes packet filter for this NIO.
|
||||
@ -124,8 +129,8 @@ class NIO(object):
|
||||
raise DynamipsError("Unknown direction {} to unbind filter:".format(direction))
|
||||
dynamips_direction = self._dynamips_direction[direction]
|
||||
|
||||
self._hypervisor.send("nio unbind_filter {name} {direction}".format(name=self._name,
|
||||
direction=dynamips_direction))
|
||||
yield from self._hypervisor.send("nio unbind_filter {name} {direction}".format(name=self._name,
|
||||
direction=dynamips_direction))
|
||||
|
||||
if direction == "in":
|
||||
self._input_filter = None
|
||||
@ -135,6 +140,7 @@ class NIO(object):
|
||||
self._input_filter = None
|
||||
self._output_filter = None
|
||||
|
||||
@asyncio.coroutine
|
||||
def setup_filter(self, direction, options):
|
||||
"""
|
||||
Setups a packet filter bound with this NIO.
|
||||
@ -157,9 +163,9 @@ class NIO(object):
|
||||
raise DynamipsError("Unknown direction {} to setup filter:".format(direction))
|
||||
dynamips_direction = self._dynamips_direction[direction]
|
||||
|
||||
self._hypervisor.send("nio setup_filter {name} {direction} {options}".format(name=self._name,
|
||||
direction=dynamips_direction,
|
||||
options=options))
|
||||
yield from self._hypervisor.send("nio setup_filter {name} {direction} {options}".format(name=self._name,
|
||||
direction=dynamips_direction,
|
||||
options=options))
|
||||
|
||||
if direction == "in":
|
||||
self._input_filter_options = options
|
||||
@ -189,6 +195,7 @@ class NIO(object):
|
||||
|
||||
return self._output_filter, self._output_filter_options
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_stats(self):
|
||||
"""
|
||||
Gets statistics for this NIO.
|
||||
@ -196,25 +203,16 @@ class NIO(object):
|
||||
:returns: NIO statistics (string with packets in, packets out, bytes in, bytes out)
|
||||
"""
|
||||
|
||||
return self._hypervisor.send("nio get_stats {}".format(self._name))[0]
|
||||
stats = yield from self._hypervisor.send("nio get_stats {}".format(self._name))
|
||||
return stats[0]
|
||||
|
||||
@asyncio.coroutine
|
||||
def reset_stats(self):
|
||||
"""
|
||||
Resets statistics for this NIO.
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio reset_stats {}".format(self._name))
|
||||
|
||||
def set_bandwidth(self, bandwidth):
|
||||
"""
|
||||
Sets bandwidth constraint.
|
||||
|
||||
:param bandwidth: bandwidth integer value (in Kb/s)
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio set_bandwidth {name} {bandwidth}".format(name=self._name,
|
||||
bandwidth=bandwidth))
|
||||
self._bandwidth = bandwidth
|
||||
yield from self._hypervisor.send("nio reset_stats {}".format(self._name))
|
||||
|
||||
@property
|
||||
def bandwidth(self):
|
||||
@ -226,6 +224,17 @@ class NIO(object):
|
||||
|
||||
return self._bandwidth
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_bandwidth(self, bandwidth):
|
||||
"""
|
||||
Sets bandwidth constraint.
|
||||
|
||||
:param bandwidth: bandwidth integer value (in Kb/s)
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send("nio set_bandwidth {name} {bandwidth}".format(name=self._name, bandwidth=bandwidth))
|
||||
self._bandwidth = bandwidth
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
NIO string representation.
|
@ -19,6 +19,7 @@
|
||||
Interface for FIFO NIOs.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
@ -26,7 +27,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_FIFO(NIO):
|
||||
|
||||
"""
|
||||
Dynamips FIFO NIO.
|
||||
|
||||
@ -44,10 +44,6 @@ class NIO_FIFO(NIO):
|
||||
NIO_FIFO._instance_count += 1
|
||||
self._name = 'nio_fifo' + str(self._id)
|
||||
|
||||
self._hypervisor.send("nio create_fifo {}".format(self._name))
|
||||
|
||||
log.info("NIO FIFO {name} created.".format(name=self._name))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
@ -56,6 +52,13 @@ class NIO_FIFO(NIO):
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from self._hypervisor.send("nio create_fifo {}".format(self._name))
|
||||
log.info("NIO FIFO {name} created.".format(name=self._name))
|
||||
|
||||
@asyncio.coroutine
|
||||
def crossconnect(self, nio):
|
||||
"""
|
||||
Establishes a cross-connect between this FIFO NIO and another one.
|
||||
@ -63,7 +66,7 @@ class NIO_FIFO(NIO):
|
||||
:param nio: FIFO NIO instance
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio crossconnect_fifo {name} {nio}".format(name=self._name,
|
||||
nio=nio))
|
||||
yield from self._hypervisor.send("nio crossconnect_fifo {name} {nio}".format(name=self._name,
|
||||
nio=nio))
|
||||
|
||||
log.info("NIO FIFO {name} crossconnected with {nio_name}.".format(name=self._name, nio_name=nio.name))
|
@ -19,6 +19,7 @@
|
||||
Interface for generic Ethernet NIOs (PCAP library).
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
@ -26,7 +27,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_GenericEthernet(NIO):
|
||||
|
||||
"""
|
||||
Dynamips generic Ethernet NIO.
|
||||
|
||||
@ -46,11 +46,7 @@ class NIO_GenericEthernet(NIO):
|
||||
self._name = 'nio_gen_eth' + str(self._id)
|
||||
self._ethernet_device = ethernet_device
|
||||
|
||||
self._hypervisor.send("nio create_gen_eth {name} {eth_device}".format(name=self._name,
|
||||
eth_device=ethernet_device))
|
||||
|
||||
log.info("NIO Generic Ethernet {name} created with device {device}".format(name=self._name,
|
||||
device=ethernet_device))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
@ -60,6 +56,15 @@ class NIO_GenericEthernet(NIO):
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from self._hypervisor.send("nio create_gen_eth {name} {eth_device}".format(name=self._name,
|
||||
eth_device=self._ethernet_device))
|
||||
|
||||
log.info("NIO Generic Ethernet {name} created with device {device}".format(name=self._name,
|
||||
device=self._ethernet_device))
|
||||
|
||||
@property
|
||||
def ethernet_device(self):
|
||||
"""
|
@ -19,6 +19,7 @@
|
||||
Interface for Linux Ethernet NIOs (Linux only).
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
@ -26,7 +27,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_LinuxEthernet(NIO):
|
||||
|
||||
"""
|
||||
Dynamips Linux Ethernet NIO.
|
||||
|
||||
@ -46,12 +46,6 @@ class NIO_LinuxEthernet(NIO):
|
||||
self._name = 'nio_linux_eth' + str(self._id)
|
||||
self._ethernet_device = ethernet_device
|
||||
|
||||
self._hypervisor.send("nio create_linux_eth {name} {eth_device}".format(name=self._name,
|
||||
eth_device=ethernet_device))
|
||||
|
||||
log.info("NIO Linux Ethernet {name} created with device {device}".format(name=self._name,
|
||||
device=ethernet_device))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
@ -60,6 +54,15 @@ class NIO_LinuxEthernet(NIO):
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from self._hypervisor.send("nio create_linux_eth {name} {eth_device}".format(name=self._name,
|
||||
eth_device=self._ethernet_device))
|
||||
|
||||
log.info("NIO Linux Ethernet {name} created with device {device}".format(name=self._name,
|
||||
device=self._ethernet_device))
|
||||
|
||||
@property
|
||||
def ethernet_device(self):
|
||||
"""
|
@ -19,6 +19,7 @@
|
||||
Interface for multicast NIOs.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
@ -26,7 +27,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_Mcast(NIO):
|
||||
|
||||
"""
|
||||
Dynamips Linux Ethernet NIO.
|
||||
|
||||
@ -49,14 +49,6 @@ class NIO_Mcast(NIO):
|
||||
self._port = port
|
||||
self._ttl = 1 # default TTL
|
||||
|
||||
self._hypervisor.send("nio create_mcast {name} {mgroup} {mport}".format(name=self._name,
|
||||
mgroup=group,
|
||||
mport=port))
|
||||
|
||||
log.info("NIO Multicast {name} created with mgroup={group}, mport={port}".format(name=self._name,
|
||||
group=group,
|
||||
port=port))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
@ -65,6 +57,17 @@ class NIO_Mcast(NIO):
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from self._hypervisor.send("nio create_mcast {name} {mgroup} {mport}".format(name=self._name,
|
||||
mgroup=self._group,
|
||||
mport=self._port))
|
||||
|
||||
log.info("NIO Multicast {name} created with mgroup={group}, mport={port}".format(name=self._name,
|
||||
group=self._group,
|
||||
port=self._port))
|
||||
|
||||
@property
|
||||
def group(self):
|
||||
"""
|
||||
@ -95,14 +98,13 @@ class NIO_Mcast(NIO):
|
||||
|
||||
return self._ttl
|
||||
|
||||
@ttl.setter
|
||||
def ttl(self, ttl):
|
||||
def set_ttl(self, ttl):
|
||||
"""
|
||||
Sets the TTL for the multicast address
|
||||
|
||||
:param ttl: TTL value
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio set_mcast_ttl {name} {ttl}".format(name=self._name,
|
||||
ttl=ttl))
|
||||
yield from self._hypervisor.send("nio set_mcast_ttl {name} {ttl}".format(name=self._name,
|
||||
ttl=ttl))
|
||||
self._ttl = ttl
|
@ -19,6 +19,7 @@
|
||||
Interface for dummy NIOs (mostly for tests).
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
@ -26,7 +27,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_Null(NIO):
|
||||
|
||||
"""
|
||||
Dynamips NULL NIO.
|
||||
|
||||
@ -44,9 +44,6 @@ class NIO_Null(NIO):
|
||||
NIO_Null._instance_count += 1
|
||||
self._name = 'nio_null' + str(self._id)
|
||||
|
||||
self._hypervisor.send("nio create_null {}".format(self._name))
|
||||
log.info("NIO NULL {name} created.".format(name=self._name))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
@ -54,3 +51,9 @@ class NIO_Null(NIO):
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from self._hypervisor.send("nio create_null {}".format(self._name))
|
||||
log.info("NIO NULL {name} created.".format(name=self._name))
|
@ -19,6 +19,7 @@
|
||||
Interface for TAP NIOs (UNIX based OSes only).
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
@ -26,7 +27,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_TAP(NIO):
|
||||
|
||||
"""
|
||||
Dynamips TAP NIO.
|
||||
|
||||
@ -46,12 +46,6 @@ class NIO_TAP(NIO):
|
||||
self._name = 'nio_tap' + str(self._id)
|
||||
self._tap_device = tap_device
|
||||
|
||||
self._hypervisor.send("nio create_tap {name} {tap}".format(name=self._name,
|
||||
tap=tap_device))
|
||||
|
||||
log.info("NIO TAP {name} created with device {device}".format(name=self._name,
|
||||
device=tap_device))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
@ -60,6 +54,12 @@ class NIO_TAP(NIO):
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from self._hypervisor.send("nio create_tap {name} {tap}".format(name=self._name, tap=self._tap_device))
|
||||
log.info("NIO TAP {name} created with device {device}".format(name=self._name, device=self._tap_device))
|
||||
|
||||
@property
|
||||
def tap_device(self):
|
||||
"""
|
@ -19,6 +19,7 @@
|
||||
Interface for UDP NIOs.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
@ -26,7 +27,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_UDP(NIO):
|
||||
|
||||
"""
|
||||
Dynamips UDP NIO.
|
||||
|
||||
@ -50,16 +50,6 @@ class NIO_UDP(NIO):
|
||||
self._rhost = rhost
|
||||
self._rport = rport
|
||||
|
||||
self._hypervisor.send("nio create_udp {name} {lport} {rhost} {rport}".format(name=self._name,
|
||||
lport=lport,
|
||||
rhost=rhost,
|
||||
rport=rport))
|
||||
|
||||
log.info("NIO UDP {name} created with lport={lport}, rhost={rhost}, rport={rport}".format(name=self._name,
|
||||
lport=lport,
|
||||
rhost=rhost,
|
||||
rport=rport))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
@ -68,6 +58,19 @@ class NIO_UDP(NIO):
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from self._hypervisor.send("nio create_udp {name} {lport} {rhost} {rport}".format(name=self._name,
|
||||
lport=self._lport,
|
||||
rhost=self._rhost,
|
||||
rport=self._rport))
|
||||
|
||||
log.info("NIO UDP {name} created with lport={lport}, rhost={rhost}, rport={rport}".format(name=self._name,
|
||||
lport=self._lport,
|
||||
rhost=self._rhost,
|
||||
rport=self._rport))
|
||||
|
||||
@property
|
||||
def lport(self):
|
||||
"""
|
@ -19,6 +19,7 @@
|
||||
Interface for automatic UDP NIOs.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
@ -26,7 +27,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_UDP_auto(NIO):
|
||||
|
||||
"""
|
||||
Dynamips auto UDP NIO.
|
||||
|
||||
@ -48,15 +48,7 @@ class NIO_UDP_auto(NIO):
|
||||
self._name = 'nio_udp_auto' + str(self._id)
|
||||
|
||||
self._laddr = laddr
|
||||
self._lport = int(self._hypervisor.send("nio create_udp_auto {name} {laddr} {lport_start} {lport_end}".format(name=self._name,
|
||||
laddr=laddr,
|
||||
lport_start=lport_start,
|
||||
lport_end=lport_end))[0])
|
||||
|
||||
log.info("NIO UDP AUTO {name} created with laddr={laddr}, lport_start={start}, lport_end={end}".format(name=self._name,
|
||||
laddr=laddr,
|
||||
start=lport_start,
|
||||
end=lport_end))
|
||||
self._lport = None
|
||||
self._raddr = None
|
||||
self._rport = None
|
||||
|
||||
@ -68,6 +60,20 @@ class NIO_UDP_auto(NIO):
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
port = yield from self._hypervisor.send("nio create_udp_auto {name} {laddr} {lport_start} {lport_end}".format(name=self._name,
|
||||
laddr=self._laddr,
|
||||
lport_start=self._lport_start,
|
||||
lport_end=self._lport_end))
|
||||
self._lport = int(port[0])
|
||||
|
||||
log.info("NIO UDP AUTO {name} created with laddr={laddr}, lport_start={start}, lport_end={end}".format(name=self._name,
|
||||
laddr=self._laddr,
|
||||
start=self._lport_start,
|
||||
end=self._lport_end))
|
||||
|
||||
@property
|
||||
def laddr(self):
|
||||
"""
|
||||
@ -108,6 +114,7 @@ class NIO_UDP_auto(NIO):
|
||||
|
||||
return self._rport
|
||||
|
||||
@asyncio.coroutine
|
||||
def connect(self, raddr, rport):
|
||||
"""
|
||||
Connects this NIO to a remote socket
|
||||
@ -116,9 +123,9 @@ class NIO_UDP_auto(NIO):
|
||||
:param rport: remote port number
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio connect_udp_auto {name} {raddr} {rport}".format(name=self._name,
|
||||
raddr=raddr,
|
||||
rport=rport))
|
||||
yield from self._hypervisor.send("nio connect_udp_auto {name} {raddr} {rport}".format(name=self._name,
|
||||
raddr=raddr,
|
||||
rport=rport))
|
||||
self._raddr = raddr
|
||||
self._rport = rport
|
||||
|
@ -19,6 +19,7 @@
|
||||
Interface for UNIX NIOs (Unix based OSes only).
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
@ -26,7 +27,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_UNIX(NIO):
|
||||
|
||||
"""
|
||||
Dynamips UNIX NIO.
|
||||
|
||||
@ -48,14 +48,6 @@ class NIO_UNIX(NIO):
|
||||
self._local_file = local_file
|
||||
self._remote_file = remote_file
|
||||
|
||||
self._hypervisor.send("nio create_unix {name} {local} {remote}".format(name=self._name,
|
||||
local=local_file,
|
||||
remote=remote_file))
|
||||
|
||||
log.info("NIO UNIX {name} created with local file {local} and remote file {remote}".format(name=self._name,
|
||||
local=local_file,
|
||||
remote=remote_file))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
@ -64,6 +56,17 @@ class NIO_UNIX(NIO):
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from self._hypervisor.send("nio create_unix {name} {local} {remote}".format(name=self._name,
|
||||
local=self._local_file,
|
||||
remote=self._remote_file))
|
||||
|
||||
log.info("NIO UNIX {name} created with local file {local} and remote file {remote}".format(name=self._name,
|
||||
local=self._local_file,
|
||||
remote=self._remote_file))
|
||||
|
||||
@property
|
||||
def local_file(self):
|
||||
"""
|
@ -26,7 +26,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_VDE(NIO):
|
||||
|
||||
"""
|
||||
Dynamips VDE NIO.
|
||||
|
@ -29,7 +29,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C1700(Router):
|
||||
|
||||
"""
|
||||
Dynamips c1700 router.
|
||||
|
@ -31,7 +31,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C2600(Router):
|
||||
|
||||
"""
|
||||
Dynamips c2600 router.
|
||||
|
@ -28,7 +28,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C2691(Router):
|
||||
|
||||
"""
|
||||
Dynamips c2691 router.
|
||||
|
@ -28,7 +28,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C3600(Router):
|
||||
|
||||
"""
|
||||
Dynamips c3600 router.
|
||||
|
@ -28,7 +28,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C3725(Router):
|
||||
|
||||
"""
|
||||
Dynamips c3725 router.
|
||||
|
@ -28,7 +28,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C3745(Router):
|
||||
|
||||
"""
|
||||
Dynamips c3745 router.
|
||||
|
@ -30,7 +30,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C7200(Router):
|
||||
|
||||
"""
|
||||
Dynamips c7200 router (model is 7206).
|
||||
|
||||
@ -228,9 +227,9 @@ class C7200(Router):
|
||||
powered_on=power_supply))
|
||||
|
||||
log.info("router {name} [id={id}]: power supply {power_supply_id} state updated to {powered_on}".format(name=self._name,
|
||||
id=self._id,
|
||||
power_supply_id=power_supply_id,
|
||||
powered_on=power_supply))
|
||||
id=self._id,
|
||||
power_supply_id=power_supply_id,
|
||||
powered_on=power_supply))
|
||||
power_supply_id += 1
|
||||
|
||||
self._power_supplies = power_supplies
|
1514
gns3server/modules/dynamips/nodes/router.py
Normal file
1514
gns3server/modules/dynamips/nodes/router.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -185,7 +185,7 @@ class PortManager:
|
||||
"""
|
||||
|
||||
if port in self._used_tcp_ports:
|
||||
raise HTTPConflict(text="TCP port already {} in use on host".format(port, self._console_host))
|
||||
raise HTTPConflict(text="TCP port {} already in use on host".format(port, self._console_host))
|
||||
self._used_tcp_ports.add(port)
|
||||
return port
|
||||
|
||||
@ -221,7 +221,7 @@ class PortManager:
|
||||
"""
|
||||
|
||||
if port in self._used_udp_ports:
|
||||
raise HTTPConflict(text="UDP port already {} in use on host".format(port, self._console_host))
|
||||
raise HTTPConflict(text="UDP port {} already in use on host".format(port, self._console_host))
|
||||
self._used_udp_ports.add(port)
|
||||
|
||||
def release_udp_port(self, port):
|
||||
|
@ -254,10 +254,10 @@ class VPCSVM(BaseVM):
|
||||
if self.is_running():
|
||||
self._terminate_process()
|
||||
try:
|
||||
yield from asyncio.wait_for(self._process.wait(), timeout=10)
|
||||
yield from asyncio.wait_for(self._process.wait(), timeout=3)
|
||||
except asyncio.TimeoutError:
|
||||
self._process.kill()
|
||||
if self._process.poll() is None:
|
||||
if self._process.returncode is None:
|
||||
log.warn("VPCS process {} is still running".format(self._process.pid))
|
||||
|
||||
self._process = None
|
||||
|
@ -1,578 +0,0 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Dynamips server module.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import base64
|
||||
import tempfile
|
||||
import shutil
|
||||
import glob
|
||||
import socket
|
||||
from gns3server.modules import IModule
|
||||
from gns3server.config import Config
|
||||
from gns3server.builtins.interfaces import get_windows_interfaces
|
||||
|
||||
from .hypervisor import Hypervisor
|
||||
from .hypervisor_manager import HypervisorManager
|
||||
from .dynamips_error import DynamipsError
|
||||
|
||||
# Nodes
|
||||
from .nodes.router import Router
|
||||
from .nodes.c1700 import C1700
|
||||
from .nodes.c2600 import C2600
|
||||
from .nodes.c2691 import C2691
|
||||
from .nodes.c3600 import C3600
|
||||
from .nodes.c3725 import C3725
|
||||
from .nodes.c3745 import C3745
|
||||
from .nodes.c7200 import C7200
|
||||
from .nodes.bridge import Bridge
|
||||
from .nodes.ethernet_switch import EthernetSwitch
|
||||
from .nodes.atm_switch import ATMSwitch
|
||||
from .nodes.atm_bridge import ATMBridge
|
||||
from .nodes.frame_relay_switch import FrameRelaySwitch
|
||||
from .nodes.hub import Hub
|
||||
|
||||
# Adapters
|
||||
from .adapters.c7200_io_2fe import C7200_IO_2FE
|
||||
from .adapters.c7200_io_fe import C7200_IO_FE
|
||||
from .adapters.c7200_io_ge_e import C7200_IO_GE_E
|
||||
from .adapters.nm_16esw import NM_16ESW
|
||||
from .adapters.nm_1e import NM_1E
|
||||
from .adapters.nm_1fe_tx import NM_1FE_TX
|
||||
from .adapters.nm_4e import NM_4E
|
||||
from .adapters.nm_4t import NM_4T
|
||||
from .adapters.pa_2fe_tx import PA_2FE_TX
|
||||
from .adapters.pa_4e import PA_4E
|
||||
from .adapters.pa_4t import PA_4T
|
||||
from .adapters.pa_8e import PA_8E
|
||||
from .adapters.pa_8t import PA_8T
|
||||
from .adapters.pa_a1 import PA_A1
|
||||
from .adapters.pa_fe_tx import PA_FE_TX
|
||||
from .adapters.pa_ge import PA_GE
|
||||
from .adapters.pa_pos_oc3 import PA_POS_OC3
|
||||
from .adapters.wic_1t import WIC_1T
|
||||
from .adapters.wic_2t import WIC_2T
|
||||
from .adapters.wic_1enet import WIC_1ENET
|
||||
|
||||
# NIOs
|
||||
from .nios.nio_udp import NIO_UDP
|
||||
from .nios.nio_udp_auto import NIO_UDP_auto
|
||||
from .nios.nio_unix import NIO_UNIX
|
||||
from .nios.nio_vde import NIO_VDE
|
||||
from .nios.nio_tap import NIO_TAP
|
||||
from .nios.nio_generic_ethernet import NIO_GenericEthernet
|
||||
from .nios.nio_linux_ethernet import NIO_LinuxEthernet
|
||||
from .nios.nio_fifo import NIO_FIFO
|
||||
from .nios.nio_mcast import NIO_Mcast
|
||||
from .nios.nio_null import NIO_Null
|
||||
|
||||
from .backends import vm
|
||||
from .backends import ethsw
|
||||
from .backends import ethhub
|
||||
from .backends import frsw
|
||||
from .backends import atmsw
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Dynamips(IModule):
|
||||
|
||||
"""
|
||||
Dynamips module.
|
||||
|
||||
:param name: module name
|
||||
:param args: arguments for the module
|
||||
:param kwargs: named arguments for the module
|
||||
"""
|
||||
|
||||
def __init__(self, name, *args, **kwargs):
|
||||
|
||||
# get the Dynamips location
|
||||
config = Config.instance()
|
||||
dynamips_config = config.get_section_config(name.upper())
|
||||
self._dynamips = dynamips_config.get("dynamips_path")
|
||||
if not self._dynamips or not os.path.isfile(self._dynamips):
|
||||
paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep)
|
||||
# look for Dynamips in the current working directory and $PATH
|
||||
for path in paths:
|
||||
try:
|
||||
if "dynamips" in os.listdir(path) and os.access(os.path.join(path, "dynamips"), os.X_OK):
|
||||
self._dynamips = os.path.join(path, "dynamips")
|
||||
break
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
if not self._dynamips:
|
||||
log.warning("dynamips binary couldn't be found!")
|
||||
elif not os.access(self._dynamips, os.X_OK):
|
||||
log.warning("dynamips is not executable")
|
||||
|
||||
IModule.__init__(self, name, *args, **kwargs)
|
||||
self._hypervisor_manager = None
|
||||
self._hypervisor_manager_settings = {}
|
||||
self._routers = {}
|
||||
self._ethernet_switches = {}
|
||||
self._frame_relay_switches = {}
|
||||
self._atm_switches = {}
|
||||
self._ethernet_hubs = {}
|
||||
self._projects_dir = kwargs["projects_dir"]
|
||||
self._tempdir = kwargs["temp_dir"]
|
||||
self._working_dir = self._projects_dir
|
||||
self._host = dynamips_config.get("host", kwargs["host"])
|
||||
self._console_host = dynamips_config.get("console_host", kwargs["console_host"])
|
||||
|
||||
if not sys.platform.startswith("win32"):
|
||||
# FIXME: pickle issues Windows
|
||||
self._callback = self.add_periodic_callback(self._check_hypervisors, 5000)
|
||||
self._callback.start()
|
||||
|
||||
def stop(self, signum=None):
|
||||
"""
|
||||
Properly stops the module.
|
||||
|
||||
:param signum: signal number (if called by the signal handler)
|
||||
"""
|
||||
|
||||
if not sys.platform.startswith("win32"):
|
||||
self._callback.stop()
|
||||
|
||||
# automatically save configs for all router instances
|
||||
for router_id in self._routers:
|
||||
router = self._routers[router_id]
|
||||
try:
|
||||
router.save_configs()
|
||||
except DynamipsError:
|
||||
continue
|
||||
|
||||
# stop all Dynamips hypervisors
|
||||
if self._hypervisor_manager:
|
||||
self._hypervisor_manager.stop_all_hypervisors()
|
||||
|
||||
self.delete_dynamips_files()
|
||||
IModule.stop(self, signum) # this will stop the I/O loop
|
||||
|
||||
def _check_hypervisors(self):
|
||||
"""
|
||||
Periodic callback to check if Dynamips hypervisors are running.
|
||||
|
||||
Sends a notification to the client if not.
|
||||
"""
|
||||
|
||||
if self._hypervisor_manager:
|
||||
for hypervisor in self._hypervisor_manager.hypervisors:
|
||||
if hypervisor.started and not hypervisor.is_running():
|
||||
notification = {"module": self.name}
|
||||
stdout = hypervisor.read_stdout()
|
||||
device_names = []
|
||||
for device in hypervisor.devices:
|
||||
device_names.append(device.name)
|
||||
notification["message"] = "Dynamips has stopped running"
|
||||
notification["details"] = stdout
|
||||
notification["devices"] = device_names
|
||||
self.send_notification("{}.dynamips_stopped".format(self.name), notification)
|
||||
hypervisor.stop()
|
||||
|
||||
def get_device_instance(self, device_id, instance_dict):
|
||||
"""
|
||||
Returns a device instance.
|
||||
|
||||
:param device_id: device identifier
|
||||
:param instance_dict: dictionary containing the instances
|
||||
|
||||
:returns: device instance
|
||||
"""
|
||||
|
||||
if device_id not in instance_dict:
|
||||
log.debug("device ID {} doesn't exist".format(device_id), exc_info=1)
|
||||
self.send_custom_error("Device ID {} doesn't exist".format(device_id))
|
||||
return None
|
||||
return instance_dict[device_id]
|
||||
|
||||
def delete_dynamips_files(self):
|
||||
"""
|
||||
Deletes useless Dynamips files from the working directory
|
||||
"""
|
||||
|
||||
files = glob.glob(os.path.join(self._working_dir, "dynamips", "*.ghost"))
|
||||
files += glob.glob(os.path.join(self._working_dir, "dynamips", "*_lock"))
|
||||
files += glob.glob(os.path.join(self._working_dir, "dynamips", "ilt_*"))
|
||||
files += glob.glob(os.path.join(self._working_dir, "dynamips", "c[0-9][0-9][0-9][0-9]_*_rommon_vars"))
|
||||
files += glob.glob(os.path.join(self._working_dir, "dynamips", "c[0-9][0-9][0-9][0-9]_*_ssa"))
|
||||
for file in files:
|
||||
try:
|
||||
log.debug("deleting file {}".format(file))
|
||||
os.remove(file)
|
||||
except OSError as e:
|
||||
log.warn("could not delete file {}: {}".format(file, e))
|
||||
continue
|
||||
|
||||
@IModule.route("dynamips.reset")
|
||||
def reset(self, request=None):
|
||||
"""
|
||||
Resets the module (JSON-RPC notification).
|
||||
|
||||
:param request: JSON request (not used)
|
||||
"""
|
||||
|
||||
# automatically save configs for all router instances
|
||||
for router_id in self._routers:
|
||||
router = self._routers[router_id]
|
||||
try:
|
||||
router.save_configs()
|
||||
except DynamipsError:
|
||||
continue
|
||||
|
||||
# stop all Dynamips hypervisors
|
||||
if self._hypervisor_manager:
|
||||
self._hypervisor_manager.stop_all_hypervisors()
|
||||
|
||||
# resets the instance counters
|
||||
Router.reset()
|
||||
EthernetSwitch.reset()
|
||||
Hub.reset()
|
||||
FrameRelaySwitch.reset()
|
||||
ATMSwitch.reset()
|
||||
NIO_UDP.reset()
|
||||
NIO_UDP_auto.reset()
|
||||
NIO_UNIX.reset()
|
||||
NIO_VDE.reset()
|
||||
NIO_TAP.reset()
|
||||
NIO_GenericEthernet.reset()
|
||||
NIO_LinuxEthernet.reset()
|
||||
NIO_FIFO.reset()
|
||||
NIO_Mcast.reset()
|
||||
NIO_Null.reset()
|
||||
|
||||
self._routers.clear()
|
||||
self._ethernet_switches.clear()
|
||||
self._frame_relay_switches.clear()
|
||||
self._atm_switches.clear()
|
||||
|
||||
self.delete_dynamips_files()
|
||||
|
||||
self._hypervisor_manager = None
|
||||
self._working_dir = self._projects_dir
|
||||
log.info("dynamips module has been reset")
|
||||
|
||||
def start_hypervisor_manager(self):
|
||||
"""
|
||||
Starts the hypervisor manager.
|
||||
"""
|
||||
|
||||
# check if Dynamips path exists
|
||||
if not os.path.isfile(self._dynamips):
|
||||
raise DynamipsError("Dynamips executable {} doesn't exist".format(self._dynamips))
|
||||
|
||||
# check if Dynamips is executable
|
||||
if not os.access(self._dynamips, os.X_OK):
|
||||
raise DynamipsError("Dynamips {} is not executable".format(self._dynamips))
|
||||
|
||||
workdir = os.path.join(self._working_dir, "dynamips")
|
||||
try:
|
||||
os.makedirs(workdir)
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not create working directory {}".format(e))
|
||||
|
||||
# check if the working directory is writable
|
||||
if not os.access(workdir, os.W_OK):
|
||||
raise DynamipsError("Cannot write to working directory {}".format(workdir))
|
||||
|
||||
log.info("starting the hypervisor manager with Dynamips working directory set to '{}'".format(workdir))
|
||||
self._hypervisor_manager = HypervisorManager(self._dynamips, workdir, self._host, self._console_host)
|
||||
|
||||
for name, value in self._hypervisor_manager_settings.items():
|
||||
if hasattr(self._hypervisor_manager, name) and getattr(self._hypervisor_manager, name) != value:
|
||||
setattr(self._hypervisor_manager, name, value)
|
||||
|
||||
@IModule.route("dynamips.settings")
|
||||
def settings(self, request):
|
||||
"""
|
||||
Set or update settings.
|
||||
|
||||
Optional request parameters:
|
||||
- path (path to the Dynamips executable)
|
||||
- working_dir (path to a working directory)
|
||||
- project_name
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
if request is None:
|
||||
self.send_param_error()
|
||||
return
|
||||
|
||||
log.debug("received request {}".format(request))
|
||||
|
||||
# TODO: JSON schema validation
|
||||
if not self._hypervisor_manager:
|
||||
|
||||
if "path" in request:
|
||||
self._dynamips = request.pop("path")
|
||||
|
||||
if "working_dir" in request:
|
||||
self._working_dir = request.pop("working_dir")
|
||||
log.info("this server is local")
|
||||
else:
|
||||
self._working_dir = os.path.join(self._projects_dir, request["project_name"])
|
||||
log.info("this server is remote with working directory path to {}".format(self._working_dir))
|
||||
|
||||
self._hypervisor_manager_settings = request
|
||||
|
||||
else:
|
||||
if "project_name" in request:
|
||||
# for remote server
|
||||
new_working_dir = os.path.join(self._projects_dir, request["project_name"])
|
||||
|
||||
if self._projects_dir != self._working_dir != new_working_dir:
|
||||
|
||||
# trick to avoid file locks by Dynamips on Windows
|
||||
if sys.platform.startswith("win"):
|
||||
self._hypervisor_manager.working_dir = tempfile.gettempdir()
|
||||
|
||||
if not os.path.isdir(new_working_dir):
|
||||
try:
|
||||
self.delete_dynamips_files()
|
||||
shutil.move(self._working_dir, new_working_dir)
|
||||
except OSError as e:
|
||||
log.error("could not move working directory from {} to {}: {}".format(self._working_dir,
|
||||
new_working_dir,
|
||||
e))
|
||||
return
|
||||
|
||||
elif "working_dir" in request:
|
||||
# for local server
|
||||
new_working_dir = request.pop("working_dir")
|
||||
|
||||
try:
|
||||
self._hypervisor_manager.working_dir = new_working_dir
|
||||
except DynamipsError as e:
|
||||
log.error("could not change working directory: {}".format(e))
|
||||
return
|
||||
|
||||
self._working_dir = new_working_dir
|
||||
|
||||
# apply settings to the hypervisor manager
|
||||
for name, value in request.items():
|
||||
if hasattr(self._hypervisor_manager, name) and getattr(self._hypervisor_manager, name) != value:
|
||||
setattr(self._hypervisor_manager, name, value)
|
||||
|
||||
@IModule.route("dynamips.echo")
|
||||
def echo(self, request):
|
||||
"""
|
||||
Echo end point for testing purposes.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
if request is None:
|
||||
self.send_param_error()
|
||||
else:
|
||||
log.debug("received request {}".format(request))
|
||||
self.send_response(request)
|
||||
|
||||
def create_nio(self, node, request):
|
||||
"""
|
||||
Creates a new NIO.
|
||||
|
||||
:param node: node requesting the NIO
|
||||
:param request: the original request with the
|
||||
necessary information to create the NIO
|
||||
|
||||
:returns: a NIO object
|
||||
"""
|
||||
|
||||
nio = None
|
||||
if request["nio"]["type"] == "nio_udp":
|
||||
lport = request["nio"]["lport"]
|
||||
rhost = request["nio"]["rhost"]
|
||||
rport = request["nio"]["rport"]
|
||||
try:
|
||||
# TODO: handle IPv6
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
||||
sock.connect((rhost, rport))
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e))
|
||||
# check if we have an allocated NIO UDP auto
|
||||
nio = node.hypervisor.get_nio_udp_auto(lport)
|
||||
if not nio:
|
||||
# otherwise create an NIO UDP
|
||||
nio = NIO_UDP(node.hypervisor, lport, rhost, rport)
|
||||
else:
|
||||
nio.connect(rhost, rport)
|
||||
elif request["nio"]["type"] == "nio_generic_ethernet":
|
||||
ethernet_device = request["nio"]["ethernet_device"]
|
||||
if sys.platform.startswith("win"):
|
||||
# replace the interface name by the GUID on Windows
|
||||
interfaces = get_windows_interfaces()
|
||||
npf_interface = None
|
||||
for interface in interfaces:
|
||||
if interface["name"] == ethernet_device:
|
||||
npf_interface = interface["id"]
|
||||
if not npf_interface:
|
||||
raise DynamipsError("Could not find interface {} on this host".format(ethernet_device))
|
||||
else:
|
||||
ethernet_device = npf_interface
|
||||
nio = NIO_GenericEthernet(node.hypervisor, ethernet_device)
|
||||
elif request["nio"]["type"] == "nio_linux_ethernet":
|
||||
if sys.platform.startswith("win"):
|
||||
raise DynamipsError("This NIO type is not supported on Windows")
|
||||
ethernet_device = request["nio"]["ethernet_device"]
|
||||
nio = NIO_LinuxEthernet(node.hypervisor, ethernet_device)
|
||||
elif request["nio"]["type"] == "nio_tap":
|
||||
tap_device = request["nio"]["tap_device"]
|
||||
nio = NIO_TAP(node.hypervisor, tap_device)
|
||||
elif request["nio"]["type"] == "nio_unix":
|
||||
local_file = request["nio"]["local_file"]
|
||||
remote_file = request["nio"]["remote_file"]
|
||||
nio = NIO_UNIX(node.hypervisor, local_file, remote_file)
|
||||
elif request["nio"]["type"] == "nio_vde":
|
||||
control_file = request["nio"]["control_file"]
|
||||
local_file = request["nio"]["local_file"]
|
||||
nio = NIO_VDE(node.hypervisor, control_file, local_file)
|
||||
elif request["nio"]["type"] == "nio_null":
|
||||
nio = NIO_Null(node.hypervisor)
|
||||
return nio
|
||||
|
||||
def allocate_udp_port(self, node):
|
||||
"""
|
||||
Allocates a UDP port in order to create an UDP NIO.
|
||||
|
||||
:param node: the node that needs to allocate an UDP port
|
||||
|
||||
:returns: dictionary with the allocated host/port info
|
||||
"""
|
||||
|
||||
port = node.hypervisor.allocate_udp_port()
|
||||
host = node.hypervisor.host
|
||||
|
||||
log.info("{} [id={}] has allocated UDP port {} with host {}".format(node.name,
|
||||
node.id,
|
||||
port,
|
||||
host))
|
||||
response = {"lport": port}
|
||||
return response
|
||||
|
||||
def set_ghost_ios(self, router):
|
||||
"""
|
||||
Manages Ghost IOS support.
|
||||
|
||||
:param router: Router instance
|
||||
"""
|
||||
|
||||
if not router.mmap:
|
||||
raise DynamipsError("mmap support is required to enable ghost IOS support")
|
||||
|
||||
ghost_instance = router.formatted_ghost_file()
|
||||
all_ghosts = []
|
||||
|
||||
# search of an existing ghost instance across all hypervisors
|
||||
for hypervisor in self._hypervisor_manager.hypervisors:
|
||||
all_ghosts.extend(hypervisor.ghosts)
|
||||
|
||||
if ghost_instance not in all_ghosts:
|
||||
# create a new ghost IOS instance
|
||||
ghost = Router(router.hypervisor, "ghost-" + ghost_instance, router.platform, ghost_flag=True)
|
||||
ghost.image = router.image
|
||||
# for 7200s, the NPE must be set when using an NPE-G2.
|
||||
if router.platform == "c7200":
|
||||
ghost.npe = router.npe
|
||||
ghost.ghost_status = 1
|
||||
ghost.ghost_file = ghost_instance
|
||||
ghost.ram = router.ram
|
||||
try:
|
||||
ghost.start()
|
||||
ghost.stop()
|
||||
except DynamipsError:
|
||||
raise
|
||||
finally:
|
||||
ghost.clean_delete()
|
||||
|
||||
if router.ghost_file != ghost_instance:
|
||||
# set the ghost file to the router
|
||||
router.ghost_status = 2
|
||||
router.ghost_file = ghost_instance
|
||||
|
||||
def create_config_from_file(self, local_base_config, router, destination_config_path):
|
||||
"""
|
||||
Creates a config file from a local base config
|
||||
|
||||
:param local_base_config: path the a local base config
|
||||
:param router: router instance
|
||||
:param destination_config_path: path to the destination config file
|
||||
|
||||
:returns: relative path to the created config file
|
||||
"""
|
||||
|
||||
log.info("creating config file {} from {}".format(destination_config_path, local_base_config))
|
||||
config_path = destination_config_path
|
||||
config_dir = os.path.dirname(destination_config_path)
|
||||
try:
|
||||
os.makedirs(config_dir)
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not create configs directory: {}".format(e))
|
||||
|
||||
try:
|
||||
with open(local_base_config, "r", errors="replace") as f:
|
||||
config = f.read()
|
||||
with open(config_path, "w") as f:
|
||||
config = "!\n" + config.replace("\r", "")
|
||||
config = config.replace('%h', router.name)
|
||||
f.write(config)
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not save the configuration from {} to {}: {}".format(local_base_config, config_path, e))
|
||||
return "configs" + os.sep + os.path.basename(config_path)
|
||||
|
||||
def create_config_from_base64(self, config_base64, router, destination_config_path):
|
||||
"""
|
||||
Creates a config file from a base64 encoded config.
|
||||
|
||||
:param config_base64: base64 encoded config
|
||||
:param router: router instance
|
||||
:param destination_config_path: path to the destination config file
|
||||
|
||||
:returns: relative path to the created config file
|
||||
"""
|
||||
|
||||
log.info("creating config file {} from base64".format(destination_config_path))
|
||||
config = base64.decodebytes(config_base64.encode("utf-8")).decode("utf-8")
|
||||
config = "!\n" + config.replace("\r", "")
|
||||
config = config.replace('%h', router.name)
|
||||
config_dir = os.path.dirname(destination_config_path)
|
||||
try:
|
||||
os.makedirs(config_dir)
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not create configs directory: {}".format(e))
|
||||
|
||||
config_path = destination_config_path
|
||||
try:
|
||||
with open(config_path, "w") as f:
|
||||
log.info("saving startup-config to {}".format(config_path))
|
||||
f.write(config)
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not save the configuration {}: {}".format(config_path, e))
|
||||
return "configs" + os.sep + os.path.basename(config_path)
|
@ -1,395 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import re
|
||||
import os
|
||||
from gns3server.modules import IModule
|
||||
from ..nodes.atm_switch import ATMSwitch
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
from ..schemas.atmsw import ATMSW_CREATE_SCHEMA
|
||||
from ..schemas.atmsw import ATMSW_DELETE_SCHEMA
|
||||
from ..schemas.atmsw import ATMSW_UPDATE_SCHEMA
|
||||
from ..schemas.atmsw import ATMSW_ALLOCATE_UDP_PORT_SCHEMA
|
||||
from ..schemas.atmsw import ATMSW_ADD_NIO_SCHEMA
|
||||
from ..schemas.atmsw import ATMSW_DELETE_NIO_SCHEMA
|
||||
from ..schemas.atmsw import ATMSW_START_CAPTURE_SCHEMA
|
||||
from ..schemas.atmsw import ATMSW_STOP_CAPTURE_SCHEMA
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ATMSW(object):
|
||||
|
||||
@IModule.route("dynamips.atmsw.create")
|
||||
def atmsw_create(self, request):
|
||||
"""
|
||||
Creates a new ATM switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- name (switch name)
|
||||
|
||||
Response parameters:
|
||||
- id (switch identifier)
|
||||
- name (switch name)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ATMSW_CREATE_SCHEMA):
|
||||
return
|
||||
|
||||
name = request["name"]
|
||||
try:
|
||||
if not self._hypervisor_manager:
|
||||
self.start_hypervisor_manager()
|
||||
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_simulated_device()
|
||||
atmsw = ATMSwitch(hypervisor, name)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"name": atmsw.name,
|
||||
"id": atmsw.id}
|
||||
|
||||
self._atm_switches[atmsw.id] = atmsw
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.atmsw.delete")
|
||||
def atmsw_delete(self, request):
|
||||
"""
|
||||
Deletes a ATM switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ATMSW_DELETE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the ATM switch instance
|
||||
atmsw_id = request["id"]
|
||||
atmsw = self.get_device_instance(atmsw_id, self._atm_switches)
|
||||
if not atmsw:
|
||||
return
|
||||
|
||||
try:
|
||||
atmsw.delete()
|
||||
self._hypervisor_manager.unallocate_hypervisor_for_simulated_device(atmsw)
|
||||
del self._atm_switches[atmsw_id]
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.atmsw.update")
|
||||
def atmsw_update(self, request):
|
||||
"""
|
||||
Updates a ATM switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
|
||||
Optional request parameters:
|
||||
- name (new switch name)
|
||||
|
||||
Response parameters:
|
||||
- name if changed
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ATMSW_UPDATE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the ATM switch instance
|
||||
atmsw = self.get_device_instance(request["id"], self._atm_switches)
|
||||
if not atmsw:
|
||||
return
|
||||
|
||||
response = {}
|
||||
# rename the switch if requested
|
||||
if "name" in request and atmsw.name != request["name"]:
|
||||
try:
|
||||
atmsw.name = request["name"]
|
||||
response["name"] = atmsw.name
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.atmsw.allocate_udp_port")
|
||||
def atmsw_allocate_udp_port(self, request):
|
||||
"""
|
||||
Allocates a UDP port in order to create an UDP NIO for an
|
||||
ATM switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
- port_id (port identifier)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
- lport (allocated local port)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ATMSW_ALLOCATE_UDP_PORT_SCHEMA):
|
||||
return
|
||||
|
||||
# get the ATM switch instance
|
||||
atmsw = self.get_device_instance(request["id"], self._atm_switches)
|
||||
if not atmsw:
|
||||
return
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(atmsw)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response["port_id"] = request["port_id"]
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.atmsw.add_nio")
|
||||
def atmsw_add_nio(self, request):
|
||||
"""
|
||||
Adds an NIO (Network Input/Output) for an ATM switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
- port (port identifier)
|
||||
- port_id (port identifier)
|
||||
- mappings (VCs/VPs mapped to the port)
|
||||
- nio (one of the following)
|
||||
- type "nio_udp"
|
||||
- lport (local port)
|
||||
- rhost (remote host)
|
||||
- rport (remote port)
|
||||
- type "nio_generic_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_linux_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_tap"
|
||||
- tap_device (TAP device name e.g. tap0)
|
||||
- type "nio_unix"
|
||||
- local_file (path to UNIX socket file)
|
||||
- remote_file (path to UNIX socket file)
|
||||
- type "nio_vde"
|
||||
- control_file (path to VDE control file)
|
||||
- local_file (path to VDE local file)
|
||||
- type "nio_null"
|
||||
|
||||
Response parameters:
|
||||
- port_id (unique port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ATMSW_ADD_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the ATM switch instance
|
||||
atmsw = self.get_device_instance(request["id"], self._atm_switches)
|
||||
if not atmsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
mappings = request["mappings"]
|
||||
|
||||
try:
|
||||
nio = self.create_nio(atmsw, request)
|
||||
if not nio:
|
||||
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
try:
|
||||
atmsw.add_nio(nio, port)
|
||||
pvc_entry = re.compile(r"""^([0-9]*):([0-9]*):([0-9]*)$""")
|
||||
for source, destination in mappings.items():
|
||||
match_source_pvc = pvc_entry.search(source)
|
||||
match_destination_pvc = pvc_entry.search(destination)
|
||||
if match_source_pvc and match_destination_pvc:
|
||||
# add the virtual channels mapped with this port/nio
|
||||
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 atmsw.has_port(destination_port):
|
||||
if (source_port, source_vpi, source_vci) not in atmsw.mapping and \
|
||||
(destination_port, destination_vpi, destination_vci) not in atmsw.mapping:
|
||||
atmsw.map_pvc(source_port, source_vpi, source_vci, destination_port, destination_vpi, destination_vci)
|
||||
atmsw.map_pvc(destination_port, destination_vpi, destination_vci, source_port, source_vpi, source_vci)
|
||||
else:
|
||||
# add the virtual paths mapped with this port/nio
|
||||
source_port, source_vpi = map(int, source.split(':'))
|
||||
destination_port, destination_vpi = map(int, destination.split(':'))
|
||||
if atmsw.has_port(destination_port):
|
||||
if (source_port, source_vpi) not in atmsw.mapping and (destination_port, destination_vpi) not in atmsw.mapping:
|
||||
atmsw.map_vp(source_port, source_vpi, destination_port, destination_vpi)
|
||||
atmsw.map_vp(destination_port, destination_vpi, source_port, source_vpi)
|
||||
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response({"port_id": request["port_id"]})
|
||||
|
||||
@IModule.route("dynamips.atmsw.delete_nio")
|
||||
def atmsw_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
- port (port identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ATMSW_DELETE_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the ATM switch instance
|
||||
atmsw = self.get_device_instance(request["id"], self._atm_switches)
|
||||
if not atmsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
try:
|
||||
for source, destination in atmsw.mapping.copy().items():
|
||||
if len(source) == 3 and len(destination) == 3:
|
||||
# remove the virtual channels mapped with this port/nio
|
||||
source_port, source_vpi, source_vci = source
|
||||
destination_port, destination_vpi, destination_vci = destination
|
||||
if port == source_port:
|
||||
atmsw.unmap_pvc(source_port, source_vpi, source_vci, destination_port, destination_vpi, destination_vci)
|
||||
atmsw.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
|
||||
if port == source_port:
|
||||
atmsw.unmap_vp(source_port, source_vpi, destination_port, destination_vpi)
|
||||
atmsw.unmap_vp(destination_port, destination_vpi, source_port, source_vpi)
|
||||
|
||||
nio = atmsw.remove_nio(port)
|
||||
nio.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.atmsw.start_capture")
|
||||
def atmsw_start_capture(self, request):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port (port identifier)
|
||||
- port_id (port identifier)
|
||||
- capture_file_name
|
||||
|
||||
Optional request parameters:
|
||||
- data_link_type (PCAP DLT_* value)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
- capture_file_path (path to the capture file)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ATMSW_START_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the ATM switch instance
|
||||
atmsw = self.get_device_instance(request["id"], self._atm_switches)
|
||||
if not atmsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
capture_file_name = request["capture_file_name"]
|
||||
data_link_type = request.get("data_link_type")
|
||||
|
||||
try:
|
||||
capture_file_path = os.path.join(atmsw.hypervisor.working_dir, "captures", capture_file_name)
|
||||
atmsw.start_capture(port, capture_file_path, data_link_type)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"],
|
||||
"capture_file_path": capture_file_path}
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.atmsw.stop_capture")
|
||||
def atmsw_stop_capture(self, request):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port_id (port identifier)
|
||||
- port (port number)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ATMSW_STOP_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the ATM switch instance
|
||||
atmsw = self.get_device_instance(request["id"], self._atm_switches)
|
||||
if not atmsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
try:
|
||||
atmsw.stop_capture(port)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"]}
|
||||
self.send_response(response)
|
@ -1,353 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
from gns3server.modules import IModule
|
||||
from ..nodes.hub import Hub
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
from ..schemas.ethhub import ETHHUB_CREATE_SCHEMA
|
||||
from ..schemas.ethhub import ETHHUB_DELETE_SCHEMA
|
||||
from ..schemas.ethhub import ETHHUB_UPDATE_SCHEMA
|
||||
from ..schemas.ethhub import ETHHUB_ALLOCATE_UDP_PORT_SCHEMA
|
||||
from ..schemas.ethhub import ETHHUB_ADD_NIO_SCHEMA
|
||||
from ..schemas.ethhub import ETHHUB_DELETE_NIO_SCHEMA
|
||||
from ..schemas.ethhub import ETHHUB_START_CAPTURE_SCHEMA
|
||||
from ..schemas.ethhub import ETHHUB_STOP_CAPTURE_SCHEMA
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ETHHUB(object):
|
||||
|
||||
@IModule.route("dynamips.ethhub.create")
|
||||
def ethhub_create(self, request):
|
||||
"""
|
||||
Creates a new Ethernet hub.
|
||||
|
||||
Mandatory request parameters:
|
||||
- name (hub name)
|
||||
|
||||
Response parameters:
|
||||
- id (hub identifier)
|
||||
- name (hub name)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHHUB_CREATE_SCHEMA):
|
||||
return
|
||||
|
||||
name = request["name"]
|
||||
try:
|
||||
if not self._hypervisor_manager:
|
||||
self.start_hypervisor_manager()
|
||||
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_simulated_device()
|
||||
ethhub = Hub(hypervisor, name)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"name": ethhub.name,
|
||||
"id": ethhub.id}
|
||||
|
||||
self._ethernet_hubs[ethhub.id] = ethhub
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.ethhub.delete")
|
||||
def ethhub_delete(self, request):
|
||||
"""
|
||||
Deletes a Ethernet hub.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (hub identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHHUB_DELETE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet hub instance
|
||||
ethhub_id = request["id"]
|
||||
ethhub = self.get_device_instance(ethhub_id, self._ethernet_hubs)
|
||||
if not ethhub:
|
||||
return
|
||||
|
||||
try:
|
||||
ethhub.delete()
|
||||
self._hypervisor_manager.unallocate_hypervisor_for_simulated_device(ethhub)
|
||||
del self._ethernet_hubs[ethhub_id]
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.ethhub.update")
|
||||
def ethhub_update(self, request):
|
||||
"""
|
||||
Updates a Ethernet hub.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (hub identifier)
|
||||
|
||||
Optional request parameters:
|
||||
- name (new hub name)
|
||||
|
||||
Response parameters:
|
||||
- name if changed
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHHUB_UPDATE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet hub instance
|
||||
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
|
||||
if not ethhub:
|
||||
return
|
||||
|
||||
response = {}
|
||||
# rename the hub if requested
|
||||
if "name" in request and ethhub.name != request["name"]:
|
||||
try:
|
||||
ethhub.name = request["name"]
|
||||
response["name"] = ethhub.name
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.ethhub.allocate_udp_port")
|
||||
def ethhub_allocate_udp_port(self, request):
|
||||
"""
|
||||
Allocates a UDP port in order to create an UDP NIO for an
|
||||
Ethernet hub.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (hub identifier)
|
||||
- port_id (port identifier)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
- lport (allocated local port)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHHUB_ALLOCATE_UDP_PORT_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet hub instance
|
||||
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
|
||||
if not ethhub:
|
||||
return
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(ethhub)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response["port_id"] = request["port_id"]
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.ethhub.add_nio")
|
||||
def ethhub_add_nio(self, request):
|
||||
"""
|
||||
Adds an NIO (Network Input/Output) for an Ethernet hub.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (hub identifier)
|
||||
- port (port identifier)
|
||||
- port_id (port identifier)
|
||||
- nio (one of the following)
|
||||
- type "nio_udp"
|
||||
- lport (local port)
|
||||
- rhost (remote host)
|
||||
- rport (remote port)
|
||||
- type "nio_generic_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_linux_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_tap"
|
||||
- tap_device (TAP device name e.g. tap0)
|
||||
- type "nio_unix"
|
||||
- local_file (path to UNIX socket file)
|
||||
- remote_file (path to UNIX socket file)
|
||||
- type "nio_vde"
|
||||
- control_file (path to VDE control file)
|
||||
- local_file (path to VDE local file)
|
||||
- type "nio_null"
|
||||
|
||||
Response parameters:
|
||||
- port_id (unique port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHHUB_ADD_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet hub instance
|
||||
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
|
||||
if not ethhub:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
try:
|
||||
nio = self.create_nio(ethhub, request)
|
||||
if not nio:
|
||||
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
try:
|
||||
ethhub.add_nio(nio, port)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response({"port_id": request["port_id"]})
|
||||
|
||||
@IModule.route("dynamips.ethhub.delete_nio")
|
||||
def ethhub_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (hub identifier)
|
||||
- port (port identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHHUB_DELETE_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet hub instance
|
||||
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
|
||||
if not ethhub:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
try:
|
||||
nio = ethhub.remove_nio(port)
|
||||
nio.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.ethhub.start_capture")
|
||||
def ethhub_start_capture(self, request):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port (port identifier)
|
||||
- port_id (port identifier)
|
||||
- capture_file_name
|
||||
|
||||
Optional request parameters:
|
||||
- data_link_type (PCAP DLT_* value)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
- capture_file_path (path to the capture file)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHHUB_START_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet hub instance
|
||||
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
|
||||
if not ethhub:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
capture_file_name = request["capture_file_name"]
|
||||
data_link_type = request.get("data_link_type")
|
||||
|
||||
try:
|
||||
capture_file_path = os.path.join(ethhub.hypervisor.working_dir, "captures", capture_file_name)
|
||||
ethhub.start_capture(port, capture_file_path, data_link_type)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"],
|
||||
"capture_file_path": capture_file_path}
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.ethhub.stop_capture")
|
||||
def ethhub_stop_capture(self, request):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port_id (port identifier)
|
||||
- port (port number)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHHUB_STOP_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet hub instance
|
||||
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
|
||||
if not ethhub:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
try:
|
||||
ethhub.stop_capture(port)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"]}
|
||||
self.send_response(response)
|
@ -1,382 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
from gns3server.modules import IModule
|
||||
from ..nodes.ethernet_switch import EthernetSwitch
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
from ..schemas.ethsw import ETHSW_CREATE_SCHEMA
|
||||
from ..schemas.ethsw import ETHSW_DELETE_SCHEMA
|
||||
from ..schemas.ethsw import ETHSW_UPDATE_SCHEMA
|
||||
from ..schemas.ethsw import ETHSW_ALLOCATE_UDP_PORT_SCHEMA
|
||||
from ..schemas.ethsw import ETHSW_ADD_NIO_SCHEMA
|
||||
from ..schemas.ethsw import ETHSW_DELETE_NIO_SCHEMA
|
||||
from ..schemas.ethsw import ETHSW_START_CAPTURE_SCHEMA
|
||||
from ..schemas.ethsw import ETHSW_STOP_CAPTURE_SCHEMA
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ETHSW(object):
|
||||
|
||||
@IModule.route("dynamips.ethsw.create")
|
||||
def ethsw_create(self, request):
|
||||
"""
|
||||
Creates a new Ethernet switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- name (switch name)
|
||||
|
||||
Response parameters:
|
||||
- id (switch identifier)
|
||||
- name (switch name)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHSW_CREATE_SCHEMA):
|
||||
return
|
||||
|
||||
name = request["name"]
|
||||
try:
|
||||
if not self._hypervisor_manager:
|
||||
self.start_hypervisor_manager()
|
||||
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_simulated_device()
|
||||
ethsw = EthernetSwitch(hypervisor, name)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"name": ethsw.name,
|
||||
"id": ethsw.id}
|
||||
|
||||
self._ethernet_switches[ethsw.id] = ethsw
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.ethsw.delete")
|
||||
def ethsw_delete(self, request):
|
||||
"""
|
||||
Deletes a Ethernet switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHSW_DELETE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet switch instance
|
||||
ethsw_id = request["id"]
|
||||
ethsw = self.get_device_instance(ethsw_id, self._ethernet_switches)
|
||||
if not ethsw:
|
||||
return
|
||||
|
||||
try:
|
||||
ethsw.delete()
|
||||
self._hypervisor_manager.unallocate_hypervisor_for_simulated_device(ethsw)
|
||||
del self._ethernet_switches[ethsw_id]
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.ethsw.update")
|
||||
def ethsw_update(self, request):
|
||||
"""
|
||||
Updates a Ethernet switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
|
||||
Optional request parameters:
|
||||
- name (new switch name)
|
||||
- ports (ports settings)
|
||||
|
||||
Response parameters:
|
||||
- name if changed
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHSW_UPDATE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet switch instance
|
||||
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
|
||||
if not ethsw:
|
||||
return
|
||||
|
||||
if "ports" in request:
|
||||
ports = request["ports"]
|
||||
|
||||
# update the port settings
|
||||
for port, info in ports.items():
|
||||
vlan = info["vlan"]
|
||||
port_type = info["type"]
|
||||
try:
|
||||
if port_type == "access":
|
||||
ethsw.set_access_port(int(port), vlan)
|
||||
elif port_type == "dot1q":
|
||||
ethsw.set_dot1q_port(int(port), vlan)
|
||||
elif port_type == "qinq":
|
||||
ethsw.set_qinq_port(int(port), vlan)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {}
|
||||
# rename the switch if requested
|
||||
if "name" in request and ethsw.name != request["name"]:
|
||||
try:
|
||||
ethsw.name = request["name"]
|
||||
response["name"] = ethsw.name
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.ethsw.allocate_udp_port")
|
||||
def ethsw_allocate_udp_port(self, request):
|
||||
"""
|
||||
Allocates a UDP port in order to create an UDP NIO for an
|
||||
Ethernet switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
- port_id (port identifier)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
- lport (allocated local port)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHSW_ALLOCATE_UDP_PORT_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet switch instance
|
||||
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
|
||||
if not ethsw:
|
||||
return
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(ethsw)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response["port_id"] = request["port_id"]
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.ethsw.add_nio")
|
||||
def ethsw_add_nio(self, request):
|
||||
"""
|
||||
Adds an NIO (Network Input/Output) for an Ethernet switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
- port (port identifier)
|
||||
- port_id (port identifier)
|
||||
- vlan (vlan identifier)
|
||||
- port_type ("access", "dot1q" or "qinq")
|
||||
- nio (one of the following)
|
||||
- type "nio_udp"
|
||||
- lport (local port)
|
||||
- rhost (remote host)
|
||||
- rport (remote port)
|
||||
- type "nio_generic_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_linux_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_tap"
|
||||
- tap_device (TAP device name e.g. tap0)
|
||||
- type "nio_unix"
|
||||
- local_file (path to UNIX socket file)
|
||||
- remote_file (path to UNIX socket file)
|
||||
- type "nio_vde"
|
||||
- control_file (path to VDE control file)
|
||||
- local_file (path to VDE local file)
|
||||
- type "nio_null"
|
||||
|
||||
Response parameters:
|
||||
- port_id (unique port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHSW_ADD_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet switch instance
|
||||
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
|
||||
if not ethsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
vlan = request["vlan"]
|
||||
port_type = request["port_type"]
|
||||
try:
|
||||
nio = self.create_nio(ethsw, request)
|
||||
if not nio:
|
||||
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
try:
|
||||
ethsw.add_nio(nio, port)
|
||||
if port_type == "access":
|
||||
ethsw.set_access_port(port, vlan)
|
||||
elif port_type == "dot1q":
|
||||
ethsw.set_dot1q_port(port, vlan)
|
||||
elif port_type == "qinq":
|
||||
ethsw.set_qinq_port(port, vlan)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response({"port_id": request["port_id"]})
|
||||
|
||||
@IModule.route("dynamips.ethsw.delete_nio")
|
||||
def ethsw_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
- port (port identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHSW_DELETE_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet switch instance
|
||||
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
|
||||
if not ethsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
try:
|
||||
nio = ethsw.remove_nio(port)
|
||||
nio.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.ethsw.start_capture")
|
||||
def ethsw_start_capture(self, request):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port (port identifier)
|
||||
- port_id (port identifier)
|
||||
- capture_file_name
|
||||
|
||||
Optional request parameters:
|
||||
- data_link_type (PCAP DLT_* value)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
- capture_file_path (path to the capture file)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHSW_START_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet switch instance
|
||||
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
|
||||
if not ethsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
capture_file_name = request["capture_file_name"]
|
||||
data_link_type = request.get("data_link_type")
|
||||
|
||||
try:
|
||||
capture_file_path = os.path.join(ethsw.hypervisor.working_dir, "captures", capture_file_name)
|
||||
ethsw.start_capture(port, capture_file_path, data_link_type)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"],
|
||||
"capture_file_path": capture_file_path}
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.ethsw.stop_capture")
|
||||
def ethsw_stop_capture(self, request):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port_id (port identifier)
|
||||
- port (port number)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, ETHSW_STOP_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Ethernet switch instance
|
||||
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
|
||||
if not ethsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
try:
|
||||
ethsw.stop_capture(port)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"]}
|
||||
self.send_response(response)
|
@ -1,374 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
from gns3server.modules import IModule
|
||||
from ..nodes.frame_relay_switch import FrameRelaySwitch
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
from ..schemas.frsw import FRSW_CREATE_SCHEMA
|
||||
from ..schemas.frsw import FRSW_DELETE_SCHEMA
|
||||
from ..schemas.frsw import FRSW_UPDATE_SCHEMA
|
||||
from ..schemas.frsw import FRSW_ALLOCATE_UDP_PORT_SCHEMA
|
||||
from ..schemas.frsw import FRSW_ADD_NIO_SCHEMA
|
||||
from ..schemas.frsw import FRSW_DELETE_NIO_SCHEMA
|
||||
from ..schemas.frsw import FRSW_START_CAPTURE_SCHEMA
|
||||
from ..schemas.frsw import FRSW_STOP_CAPTURE_SCHEMA
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FRSW(object):
|
||||
|
||||
@IModule.route("dynamips.frsw.create")
|
||||
def frsw_create(self, request):
|
||||
"""
|
||||
Creates a new Frame-Relay switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- name (switch name)
|
||||
|
||||
Response parameters:
|
||||
- id (switch identifier)
|
||||
- name (switch name)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, FRSW_CREATE_SCHEMA):
|
||||
return
|
||||
|
||||
name = request["name"]
|
||||
try:
|
||||
if not self._hypervisor_manager:
|
||||
self.start_hypervisor_manager()
|
||||
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_simulated_device()
|
||||
frsw = FrameRelaySwitch(hypervisor, name)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"name": frsw.name,
|
||||
"id": frsw.id}
|
||||
|
||||
self._frame_relay_switches[frsw.id] = frsw
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.frsw.delete")
|
||||
def frsw_delete(self, request):
|
||||
"""
|
||||
Deletes a Frame Relay switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, FRSW_DELETE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Frame relay switch instance
|
||||
frsw_id = request["id"]
|
||||
frsw = self.get_device_instance(frsw_id, self._frame_relay_switches)
|
||||
if not frsw:
|
||||
return
|
||||
|
||||
try:
|
||||
frsw.delete()
|
||||
self._hypervisor_manager.unallocate_hypervisor_for_simulated_device(frsw)
|
||||
del self._frame_relay_switches[frsw_id]
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.frsw.update")
|
||||
def frsw_update(self, request):
|
||||
"""
|
||||
Updates a Frame Relay switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
|
||||
Optional request parameters:
|
||||
- name (new switch name)
|
||||
|
||||
Response parameters:
|
||||
- name if updated
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, FRSW_UPDATE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Frame relay switch instance
|
||||
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
|
||||
if not frsw:
|
||||
return
|
||||
|
||||
response = {}
|
||||
# rename the switch if requested
|
||||
if "name" in request and frsw.name != request["name"]:
|
||||
try:
|
||||
frsw.name = request["name"]
|
||||
response["name"] = frsw.name
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.frsw.allocate_udp_port")
|
||||
def frsw_allocate_udp_port(self, request):
|
||||
"""
|
||||
Allocates a UDP port in order to create an UDP NIO for an
|
||||
Frame Relay switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
- port_id (port identifier)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
- lport (allocated local port)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, FRSW_ALLOCATE_UDP_PORT_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Frame relay switch instance
|
||||
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
|
||||
if not frsw:
|
||||
return
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(frsw)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response["port_id"] = request["port_id"]
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.frsw.add_nio")
|
||||
def frsw_add_nio(self, request):
|
||||
"""
|
||||
Adds an NIO (Network Input/Output) for an Frame-Relay switch.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
- port (port identifier)
|
||||
- port_id (port identifier)
|
||||
- mappings (VCs mapped to the port)
|
||||
- nio (one of the following)
|
||||
- type "nio_udp"
|
||||
- lport (local port)
|
||||
- rhost (remote host)
|
||||
- rport (remote port)
|
||||
- type "nio_generic_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_linux_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_tap"
|
||||
- tap_device (TAP device name e.g. tap0)
|
||||
- type "nio_unix"
|
||||
- local_file (path to UNIX socket file)
|
||||
- remote_file (path to UNIX socket file)
|
||||
- type "nio_vde"
|
||||
- control_file (path to VDE control file)
|
||||
- local_file (path to VDE local file)
|
||||
- type "nio_null"
|
||||
|
||||
Response parameters:
|
||||
- port_id (unique port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, FRSW_ADD_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Frame relay switch instance
|
||||
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
|
||||
if not frsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
mappings = request["mappings"]
|
||||
|
||||
try:
|
||||
nio = self.create_nio(frsw, request)
|
||||
if not nio:
|
||||
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
try:
|
||||
frsw.add_nio(nio, port)
|
||||
|
||||
# add the VCs mapped with this port/nio
|
||||
for source, destination in mappings.items():
|
||||
source_port, source_dlci = map(int, source.split(':'))
|
||||
destination_port, destination_dlci = map(int, destination.split(':'))
|
||||
if frsw.has_port(destination_port):
|
||||
if (source_port, source_dlci) not in frsw.mapping and (destination_port, destination_dlci) not in frsw.mapping:
|
||||
frsw.map_vc(source_port, source_dlci, destination_port, destination_dlci)
|
||||
frsw.map_vc(destination_port, destination_dlci, source_port, source_dlci)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response({"port_id": request["port_id"]})
|
||||
|
||||
@IModule.route("dynamips.frsw.delete_nio")
|
||||
def frsw_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (switch identifier)
|
||||
- port (port identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, FRSW_DELETE_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Frame relay switch instance
|
||||
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
|
||||
if not frsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
try:
|
||||
# remove the VCs mapped with this port/nio
|
||||
for source, destination in frsw.mapping.copy().items():
|
||||
source_port, source_dlci = source
|
||||
destination_port, destination_dlci = destination
|
||||
if port == source_port:
|
||||
frsw.unmap_vc(source_port, source_dlci, destination_port, destination_dlci)
|
||||
frsw.unmap_vc(destination_port, destination_dlci, source_port, source_dlci)
|
||||
|
||||
nio = frsw.remove_nio(port)
|
||||
nio.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.frsw.start_capture")
|
||||
def frsw_start_capture(self, request):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port (port identifier)
|
||||
- port_id (port identifier)
|
||||
- capture_file_name
|
||||
|
||||
Optional request parameters:
|
||||
- data_link_type (PCAP DLT_* value)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
- capture_file_path (path to the capture file)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, FRSW_START_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Frame relay switch instance
|
||||
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
|
||||
if not frsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
capture_file_name = request["capture_file_name"]
|
||||
data_link_type = request.get("data_link_type")
|
||||
|
||||
try:
|
||||
capture_file_path = os.path.join(frsw.hypervisor.working_dir, "captures", capture_file_name)
|
||||
frsw.start_capture(port, capture_file_path, data_link_type)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"],
|
||||
"capture_file_path": capture_file_path}
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.frsw.stop_capture")
|
||||
def frsw_stop_capture(self, request):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port_id (port identifier)
|
||||
- port (port number)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, FRSW_STOP_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the Frame relay switch instance
|
||||
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
|
||||
if not frsw:
|
||||
return
|
||||
|
||||
port = request["port"]
|
||||
try:
|
||||
frsw.stop_capture(port)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"]}
|
||||
self.send_response(response)
|
@ -1,905 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import ntpath
|
||||
import time
|
||||
from gns3server.modules import IModule
|
||||
from gns3dms.cloud.rackspace_ctrl import get_provider
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
from ..nodes.c1700 import C1700
|
||||
from ..nodes.c2600 import C2600
|
||||
from ..nodes.c2691 import C2691
|
||||
from ..nodes.c3600 import C3600
|
||||
from ..nodes.c3725 import C3725
|
||||
from ..nodes.c3745 import C3745
|
||||
from ..nodes.c7200 import C7200
|
||||
|
||||
from ..adapters.c7200_io_2fe import C7200_IO_2FE
|
||||
from ..adapters.c7200_io_fe import C7200_IO_FE
|
||||
from ..adapters.c7200_io_ge_e import C7200_IO_GE_E
|
||||
from ..adapters.nm_16esw import NM_16ESW
|
||||
from ..adapters.nm_1e import NM_1E
|
||||
from ..adapters.nm_1fe_tx import NM_1FE_TX
|
||||
from ..adapters.nm_4e import NM_4E
|
||||
from ..adapters.nm_4t import NM_4T
|
||||
from ..adapters.pa_2fe_tx import PA_2FE_TX
|
||||
from ..adapters.pa_4e import PA_4E
|
||||
from ..adapters.pa_4t import PA_4T
|
||||
from ..adapters.pa_8e import PA_8E
|
||||
from ..adapters.pa_8t import PA_8T
|
||||
from ..adapters.pa_a1 import PA_A1
|
||||
from ..adapters.pa_fe_tx import PA_FE_TX
|
||||
from ..adapters.pa_ge import PA_GE
|
||||
from ..adapters.pa_pos_oc3 import PA_POS_OC3
|
||||
from ..adapters.wic_1enet import WIC_1ENET
|
||||
from ..adapters.wic_1t import WIC_1T
|
||||
from ..adapters.wic_2t import WIC_2T
|
||||
|
||||
from ..schemas.vm import VM_CREATE_SCHEMA
|
||||
from ..schemas.vm import VM_DELETE_SCHEMA
|
||||
from ..schemas.vm import VM_START_SCHEMA
|
||||
from ..schemas.vm import VM_STOP_SCHEMA
|
||||
from ..schemas.vm import VM_SUSPEND_SCHEMA
|
||||
from ..schemas.vm import VM_RELOAD_SCHEMA
|
||||
from ..schemas.vm import VM_UPDATE_SCHEMA
|
||||
from ..schemas.vm import VM_START_CAPTURE_SCHEMA
|
||||
from ..schemas.vm import VM_STOP_CAPTURE_SCHEMA
|
||||
from ..schemas.vm import VM_SAVE_CONFIG_SCHEMA
|
||||
from ..schemas.vm import VM_EXPORT_CONFIG_SCHEMA
|
||||
from ..schemas.vm import VM_IDLEPCS_SCHEMA
|
||||
from ..schemas.vm import VM_AUTO_IDLEPC_SCHEMA
|
||||
from ..schemas.vm import VM_ALLOCATE_UDP_PORT_SCHEMA
|
||||
from ..schemas.vm import VM_ADD_NIO_SCHEMA
|
||||
from ..schemas.vm import VM_DELETE_NIO_SCHEMA
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
ADAPTER_MATRIX = {"C7200-IO-2FE": C7200_IO_2FE,
|
||||
"C7200-IO-FE": C7200_IO_FE,
|
||||
"C7200-IO-GE-E": C7200_IO_GE_E,
|
||||
"NM-16ESW": NM_16ESW,
|
||||
"NM-1E": NM_1E,
|
||||
"NM-1FE-TX": NM_1FE_TX,
|
||||
"NM-4E": NM_4E,
|
||||
"NM-4T": NM_4T,
|
||||
"PA-2FE-TX": PA_2FE_TX,
|
||||
"PA-4E": PA_4E,
|
||||
"PA-4T+": PA_4T,
|
||||
"PA-8E": PA_8E,
|
||||
"PA-8T": PA_8T,
|
||||
"PA-A1": PA_A1,
|
||||
"PA-FE-TX": PA_FE_TX,
|
||||
"PA-GE": PA_GE,
|
||||
"PA-POS-OC3": PA_POS_OC3}
|
||||
|
||||
WIC_MATRIX = {"WIC-1ENET": WIC_1ENET,
|
||||
"WIC-1T": WIC_1T,
|
||||
"WIC-2T": WIC_2T}
|
||||
|
||||
PLATFORMS = {'c1700': C1700,
|
||||
'c2600': C2600,
|
||||
'c2691': C2691,
|
||||
'c3725': C3725,
|
||||
'c3745': C3745,
|
||||
'c3600': C3600,
|
||||
'c7200': C7200}
|
||||
|
||||
|
||||
class VM(object):
|
||||
|
||||
@IModule.route("dynamips.vm.create")
|
||||
def vm_create(self, request):
|
||||
"""
|
||||
Creates a new VM (router).
|
||||
|
||||
Mandatory request parameters:
|
||||
- name (vm name)
|
||||
- platform (platform name e.g. c7200)
|
||||
- image (path to IOS image)
|
||||
- ram (amount of RAM in MB)
|
||||
|
||||
Optional request parameters:
|
||||
- console (console port number)
|
||||
- aux (auxiliary console port number)
|
||||
- mac_addr (MAC address)
|
||||
- chassis (router chassis model)
|
||||
|
||||
Response parameters:
|
||||
- id (vm identifier)
|
||||
- name (vm name)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_CREATE_SCHEMA):
|
||||
return
|
||||
|
||||
name = request["name"]
|
||||
platform = request["platform"]
|
||||
image = request["image"]
|
||||
ram = request["ram"]
|
||||
hypervisor = None
|
||||
chassis = request.get("chassis")
|
||||
router_id = request.get("router_id")
|
||||
|
||||
# Locate the image
|
||||
updated_image_path = os.path.join(self.images_directory, image)
|
||||
if os.path.isfile(updated_image_path):
|
||||
image = updated_image_path
|
||||
else:
|
||||
if not os.path.exists(self.images_directory):
|
||||
os.mkdir(self.images_directory)
|
||||
cloud_path = request.get("cloud_path", None)
|
||||
if cloud_path is not None:
|
||||
# Download the image from cloud files
|
||||
_, filename = ntpath.split(image)
|
||||
src = '{}/{}'.format(cloud_path, filename)
|
||||
provider = get_provider(self._cloud_settings)
|
||||
log.debug("Downloading file from {} to {}...".format(src, updated_image_path))
|
||||
provider.download_file(src, updated_image_path)
|
||||
log.debug("Download of {} complete.".format(src))
|
||||
image = updated_image_path
|
||||
|
||||
try:
|
||||
if platform not in PLATFORMS:
|
||||
raise DynamipsError("Unknown router platform: {}".format(platform))
|
||||
|
||||
if not self._hypervisor_manager:
|
||||
self.start_hypervisor_manager()
|
||||
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_router(image, ram)
|
||||
|
||||
if chassis:
|
||||
router = PLATFORMS[platform](hypervisor, name, router_id, chassis=chassis)
|
||||
elif platform == "c7200" and os.path.basename(image).lower().startswith("c7200p"):
|
||||
router = PLATFORMS[platform](hypervisor, name, router_id, npe="npe-g2")
|
||||
else:
|
||||
router = PLATFORMS[platform](hypervisor, name, router_id)
|
||||
router.ram = ram
|
||||
router.image = image
|
||||
if platform not in ("c1700", "c2600"):
|
||||
router.sparsemem = self._hypervisor_manager.sparse_memory_support
|
||||
router.mmap = self._hypervisor_manager.mmap_support
|
||||
if "console" in request:
|
||||
router.console = request["console"]
|
||||
if "aux" in request:
|
||||
router.aux = request["aux"]
|
||||
if "mac_addr" in request:
|
||||
router.mac_addr = request["mac_addr"]
|
||||
|
||||
# JIT sharing support
|
||||
if self._hypervisor_manager.jit_sharing_support:
|
||||
jitsharing_groups = hypervisor.jitsharing_groups
|
||||
ios_image = os.path.basename(image)
|
||||
if ios_image in jitsharing_groups:
|
||||
router.jit_sharing_group = jitsharing_groups[ios_image]
|
||||
else:
|
||||
new_jit_group = -1
|
||||
for jit_group in range(0, 127):
|
||||
if jit_group not in jitsharing_groups.values():
|
||||
new_jit_group = jit_group
|
||||
break
|
||||
if new_jit_group == -1:
|
||||
raise DynamipsError("All JIT groups are allocated!")
|
||||
router.jit_sharing_group = new_jit_group
|
||||
|
||||
# Ghost IOS support
|
||||
if self._hypervisor_manager.ghost_ios_support:
|
||||
self.set_ghost_ios(router)
|
||||
|
||||
except DynamipsError as e:
|
||||
dynamips_stdout = ""
|
||||
if hypervisor:
|
||||
hypervisor.decrease_memory_load(ram)
|
||||
if hypervisor.memory_load == 0 and not hypervisor.devices:
|
||||
hypervisor.stop()
|
||||
self._hypervisor_manager.hypervisors.remove(hypervisor)
|
||||
dynamips_stdout = hypervisor.read_stdout()
|
||||
self.send_custom_error(str(e) + dynamips_stdout)
|
||||
return
|
||||
|
||||
response = {"name": router.name,
|
||||
"id": router.id}
|
||||
defaults = router.defaults()
|
||||
response.update(defaults)
|
||||
self._routers[router.id] = router
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.vm.delete")
|
||||
def vm_delete(self, request):
|
||||
"""
|
||||
Deletes a VM (router).
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_DELETE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router_id = request["id"]
|
||||
router = self.get_device_instance(router_id, self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
try:
|
||||
router.clean_delete()
|
||||
self._hypervisor_manager.unallocate_hypervisor_for_router(router)
|
||||
del self._routers[router_id]
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.vm.start")
|
||||
def vm_start(self, request):
|
||||
"""
|
||||
Starts a VM (router)
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_START_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
try:
|
||||
router.start()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.vm.stop")
|
||||
def vm_stop(self, request):
|
||||
"""
|
||||
Stops a VM (router)
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_STOP_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
try:
|
||||
router.stop()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.vm.suspend")
|
||||
def vm_suspend(self, request):
|
||||
"""
|
||||
Suspends a VM (router)
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_SUSPEND_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
try:
|
||||
router.suspend()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.vm.reload")
|
||||
def vm_reload(self, request):
|
||||
"""
|
||||
Reloads a VM (router)
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_RELOAD_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
try:
|
||||
if router.get_status() != "inactive":
|
||||
router.stop()
|
||||
router.start()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
||||
|
||||
@IModule.route("dynamips.vm.update")
|
||||
def vm_update(self, request):
|
||||
"""
|
||||
Updates settings for a VM (router).
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
|
||||
Optional request parameters:
|
||||
- any setting to update
|
||||
- startup_config_base64 (startup-config base64 encoded)
|
||||
- private_config_base64 (private-config base64 encoded)
|
||||
|
||||
Response parameters:
|
||||
- updated settings
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_UPDATE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
response = {}
|
||||
try:
|
||||
default_startup_config_path = os.path.join(router.hypervisor.working_dir, "configs", "i{}_startup-config.cfg".format(router.id))
|
||||
default_private_config_path = os.path.join(router.hypervisor.working_dir, "configs", "i{}_private-config.cfg".format(router.id))
|
||||
|
||||
# a new startup-config has been pushed
|
||||
if "startup_config_base64" in request:
|
||||
# update the request with the new local startup-config path
|
||||
request["startup_config"] = self.create_config_from_base64(request["startup_config_base64"], router, default_startup_config_path)
|
||||
|
||||
# a new private-config has been pushed
|
||||
if "private_config_base64" in request:
|
||||
# update the request with the new local private-config path
|
||||
request["private_config"] = self.create_config_from_base64(request["private_config_base64"], router, default_private_config_path)
|
||||
|
||||
if "startup_config" in request:
|
||||
startup_config_path = request["startup_config"].replace("\\", '/')
|
||||
if os.path.isfile(startup_config_path) and startup_config_path != default_startup_config_path:
|
||||
# this is a local file set in the GUI
|
||||
startup_config_path = self.create_config_from_file(startup_config_path, router, default_startup_config_path)
|
||||
router.set_config(startup_config_path)
|
||||
else:
|
||||
router.set_config(startup_config_path)
|
||||
response["startup_config"] = startup_config_path
|
||||
del request["startup_config"]
|
||||
|
||||
if "private_config" in request:
|
||||
private_config_path = request["private_config"].replace("\\", '/')
|
||||
if os.path.isfile(private_config_path) and private_config_path != default_private_config_path:
|
||||
# this is a local file set in the GUI
|
||||
private_config_path = self.create_config_from_file(private_config_path, router, default_private_config_path)
|
||||
router.set_config(router.startup_config, private_config_path)
|
||||
else:
|
||||
router.set_config(router.startup_config, private_config_path)
|
||||
response["private_config"] = private_config_path
|
||||
del request["private_config"]
|
||||
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
# update the settings
|
||||
for name, value in request.items():
|
||||
if hasattr(router, name) and getattr(router, name) != value:
|
||||
try:
|
||||
setattr(router, name, value)
|
||||
response[name] = value
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
elif name.startswith("slot") and value in ADAPTER_MATRIX:
|
||||
slot_id = int(name[-1])
|
||||
adapter_name = value
|
||||
adapter = ADAPTER_MATRIX[adapter_name]()
|
||||
try:
|
||||
if router.slots[slot_id] and not isinstance(router.slots[slot_id], type(adapter)):
|
||||
router.slot_remove_binding(slot_id)
|
||||
router.slot_add_binding(slot_id, adapter)
|
||||
response[name] = value
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
elif name.startswith("slot") and value is None:
|
||||
slot_id = int(name[-1])
|
||||
if router.slots[slot_id]:
|
||||
try:
|
||||
router.slot_remove_binding(slot_id)
|
||||
response[name] = value
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
elif name.startswith("wic") and value in WIC_MATRIX:
|
||||
wic_slot_id = int(name[-1])
|
||||
wic_name = value
|
||||
wic = WIC_MATRIX[wic_name]()
|
||||
try:
|
||||
if router.slots[0].wics[wic_slot_id] and not isinstance(router.slots[0].wics[wic_slot_id], type(wic)):
|
||||
router.uninstall_wic(wic_slot_id)
|
||||
router.install_wic(wic_slot_id, wic)
|
||||
response[name] = value
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
elif name.startswith("wic") and value is None:
|
||||
wic_slot_id = int(name[-1])
|
||||
if router.slots[0].wics and router.slots[0].wics[wic_slot_id]:
|
||||
try:
|
||||
router.uninstall_wic(wic_slot_id)
|
||||
response[name] = value
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
# Update the ghost IOS file in case the RAM size has changed
|
||||
if self._hypervisor_manager.ghost_ios_support:
|
||||
try:
|
||||
self.set_ghost_ios(router)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.vm.start_capture")
|
||||
def vm_start_capture(self, request):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port_id (port identifier)
|
||||
- slot (slot number)
|
||||
- port (port number)
|
||||
- capture_file_name
|
||||
|
||||
Optional request parameters:
|
||||
- data_link_type (PCAP DLT_* value)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
- capture_file_path (path to the capture file)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_START_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
slot = request["slot"]
|
||||
port = request["port"]
|
||||
capture_file_name = request["capture_file_name"]
|
||||
data_link_type = request.get("data_link_type")
|
||||
|
||||
try:
|
||||
capture_file_path = os.path.join(router.hypervisor.working_dir, "captures", capture_file_name)
|
||||
router.start_capture(slot, port, capture_file_path, data_link_type)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"],
|
||||
"capture_file_path": capture_file_path}
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.vm.stop_capture")
|
||||
def vm_stop_capture(self, request):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port_id (port identifier)
|
||||
- slot (slot number)
|
||||
- port (port number)
|
||||
|
||||
Response parameters:
|
||||
- port_id (port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_STOP_CAPTURE_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
slot = request["slot"]
|
||||
port = request["port"]
|
||||
try:
|
||||
router.stop_capture(slot, port)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"port_id": request["port_id"]}
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.vm.save_config")
|
||||
def vm_save_config(self, request):
|
||||
"""
|
||||
Save the configs for a VM (router).
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_SAVE_CONFIG_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
try:
|
||||
router.save_configs()
|
||||
except DynamipsError as e:
|
||||
log.warn("could not save config to {}: {}".format(router.startup_config, e))
|
||||
|
||||
@IModule.route("dynamips.vm.export_config")
|
||||
def vm_export_config(self, request):
|
||||
"""
|
||||
Export the config from a router
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
|
||||
Response parameters:
|
||||
- startup_config_base64 (startup-config base64 encoded)
|
||||
- private_config_base64 (private-config base64 encoded)
|
||||
- False if no configuration can be extracted
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_EXPORT_CONFIG_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
response = {}
|
||||
try:
|
||||
startup_config_base64, private_config_base64 = router.extract_config()
|
||||
if startup_config_base64:
|
||||
response["startup_config_base64"] = startup_config_base64
|
||||
if private_config_base64:
|
||||
response["private_config_base64"] = private_config_base64
|
||||
except DynamipsError:
|
||||
self.send_custom_error("unable to extract configs from the NVRAM")
|
||||
return
|
||||
|
||||
if not response:
|
||||
self.send_response(False)
|
||||
else:
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.vm.idlepcs")
|
||||
def vm_idlepcs(self, request):
|
||||
"""
|
||||
Get Idle-PC proposals.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
|
||||
Optional request parameters:
|
||||
- compute (returns previously compute Idle-PC values if False)
|
||||
|
||||
Response parameters:
|
||||
- id (vm identifier)
|
||||
- idlepcs (Idle-PC values in an array)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_IDLEPCS_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
try:
|
||||
if "compute" in request and request["compute"] == False:
|
||||
idlepcs = router.show_idle_pc_prop()
|
||||
else:
|
||||
# reset the current Idle-PC value before calculating a new one
|
||||
router.idlepc = "0x0"
|
||||
idlepcs = router.get_idle_pc_prop()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response = {"id": router.id,
|
||||
"idlepcs": idlepcs}
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.vm.auto_idlepc")
|
||||
def vm_auto_idlepc(self, request):
|
||||
"""
|
||||
Auto Idle-PC calculation.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
|
||||
Response parameters:
|
||||
- id (vm identifier)
|
||||
- logs (logs for the calculation)
|
||||
- idlepc (Idle-PC value)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_AUTO_IDLEPC_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
try:
|
||||
router.idlepc = "0x0" # reset the current Idle-PC value before calculating a new one
|
||||
was_auto_started = False
|
||||
if router.get_status() != "running":
|
||||
router.start()
|
||||
was_auto_started = True
|
||||
time.sleep(20) # leave time to the router to boot
|
||||
|
||||
logs = []
|
||||
validated_idlepc = "0x0"
|
||||
idlepcs = router.get_idle_pc_prop()
|
||||
if not idlepcs:
|
||||
logs.append("No Idle-PC values found")
|
||||
|
||||
for idlepc in idlepcs:
|
||||
router.idlepc = idlepc.split()[0]
|
||||
logs.append("Trying Idle-PC value {}".format(router.idlepc))
|
||||
start_time = time.time()
|
||||
initial_cpu_usage = router.get_cpu_usage()
|
||||
logs.append("Initial CPU usage = {}%".format(initial_cpu_usage))
|
||||
time.sleep(4) # wait 4 seconds to probe the cpu again
|
||||
elapsed_time = time.time() - start_time
|
||||
cpu_elapsed_usage = router.get_cpu_usage() - initial_cpu_usage
|
||||
cpu_usage = abs(cpu_elapsed_usage * 100.0 / elapsed_time)
|
||||
logs.append("CPU usage after {:.2} seconds = {:.2}%".format(elapsed_time, cpu_usage))
|
||||
if cpu_usage > 100:
|
||||
cpu_usage = 100
|
||||
if cpu_usage < 70:
|
||||
validated_idlepc = router.idlepc
|
||||
logs.append("Idle-PC value {} has been validated".format(validated_idlepc))
|
||||
break
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
finally:
|
||||
if was_auto_started:
|
||||
router.stop()
|
||||
|
||||
response = {"id": router.id,
|
||||
"logs": logs,
|
||||
"idlepc": validated_idlepc}
|
||||
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.vm.allocate_udp_port")
|
||||
def vm_allocate_udp_port(self, request):
|
||||
"""
|
||||
Allocates a UDP port in order to create an UDP NIO.
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- port_id (unique port identifier)
|
||||
|
||||
Response parameters:
|
||||
- port_id (unique port identifier)
|
||||
- lport (allocated local port)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_ALLOCATE_UDP_PORT_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(router)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
response["port_id"] = request["port_id"]
|
||||
self.send_response(response)
|
||||
|
||||
@IModule.route("dynamips.vm.add_nio")
|
||||
def vm_add_nio(self, request):
|
||||
"""
|
||||
Adds an NIO (Network Input/Output) for a VM (router).
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- slot (slot number)
|
||||
- port (port number)
|
||||
- port_id (unique port identifier)
|
||||
- nio (one of the following)
|
||||
- type "nio_udp"
|
||||
- lport (local port)
|
||||
- rhost (remote host)
|
||||
- rport (remote port)
|
||||
- type "nio_generic_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_linux_ethernet"
|
||||
- ethernet_device (Ethernet device name e.g. eth0)
|
||||
- type "nio_tap"
|
||||
- tap_device (TAP device name e.g. tap0)
|
||||
- type "nio_unix"
|
||||
- local_file (path to UNIX socket file)
|
||||
- remote_file (path to UNIX socket file)
|
||||
- type "nio_vde"
|
||||
- control_file (path to VDE control file)
|
||||
- local_file (path to VDE local file)
|
||||
- type "nio_null"
|
||||
|
||||
Response parameters:
|
||||
- port_id (unique port identifier)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_ADD_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
slot = request["slot"]
|
||||
port = request["port"]
|
||||
try:
|
||||
nio = self.create_nio(router, request)
|
||||
if not nio:
|
||||
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
try:
|
||||
router.slot_add_nio_binding(slot, port, nio)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response({"port_id": request["port_id"]})
|
||||
|
||||
@IModule.route("dynamips.vm.delete_nio")
|
||||
def vm_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
Mandatory request parameters:
|
||||
- id (vm identifier)
|
||||
- slot (slot identifier)
|
||||
- port (port identifier)
|
||||
|
||||
Response parameters:
|
||||
- True on success
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# validate the request
|
||||
if not self.validate_request(request, VM_DELETE_NIO_SCHEMA):
|
||||
return
|
||||
|
||||
# get the router instance
|
||||
router = self.get_device_instance(request["id"], self._routers)
|
||||
if not router:
|
||||
return
|
||||
|
||||
slot = request["slot"]
|
||||
port = request["port"]
|
||||
try:
|
||||
nio = router.slot_remove_nio_binding(slot, port)
|
||||
nio.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
self.send_response(True)
|
@ -1,655 +0,0 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Manages Dynamips hypervisors (load-balancing etc.)
|
||||
"""
|
||||
|
||||
from gns3server.config import Config
|
||||
from .hypervisor import Hypervisor
|
||||
from .dynamips_error import DynamipsError
|
||||
from ..attic import find_unused_port
|
||||
from ..attic import wait_socket_is_ready
|
||||
from pkg_resources import parse_version
|
||||
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HypervisorManager(object):
|
||||
|
||||
"""
|
||||
Manages Dynamips hypervisors.
|
||||
|
||||
:param path: path to the Dynamips executable
|
||||
:param working_dir: path to a working directory
|
||||
:param host: host/address for hypervisors to listen to
|
||||
:param console_host: IP address to bind for console connections
|
||||
"""
|
||||
|
||||
def __init__(self, path, working_dir, host='127.0.0.1', console_host='0.0.0.0'):
|
||||
|
||||
self._hypervisors = []
|
||||
self._path = path
|
||||
self._working_dir = working_dir
|
||||
self._console_host = console_host
|
||||
self._host = console_host # FIXME: Dynamips must be patched to bind on a different address than the one used by the hypervisor.
|
||||
|
||||
config = Config.instance()
|
||||
dynamips_config = config.get_section_config("DYNAMIPS")
|
||||
self._hypervisor_start_port_range = dynamips_config.get("hypervisor_start_port_range", 7200)
|
||||
self._hypervisor_end_port_range = dynamips_config.get("hypervisor_end_port_range", 7700)
|
||||
self._console_start_port_range = dynamips_config.get("console_start_port_range", 2001)
|
||||
self._console_end_port_range = dynamips_config.get("console_end_port_range", 2500)
|
||||
self._aux_start_port_range = dynamips_config.get("aux_start_port_range", 2501)
|
||||
self._aux_end_port_range = dynamips_config.get("aux_end_port_range", 3000)
|
||||
self._udp_start_port_range = dynamips_config.get("udp_start_port_range", 10001)
|
||||
self._udp_end_port_range = dynamips_config.get("udp_end_port_range", 20000)
|
||||
self._ghost_ios_support = dynamips_config.get("ghost_ios_support", True)
|
||||
self._mmap_support = dynamips_config.get("mmap_support", True)
|
||||
self._jit_sharing_support = dynamips_config.get("jit_sharing_support", False)
|
||||
self._sparse_memory_support = dynamips_config.get("sparse_memory_support", True)
|
||||
self._allocate_hypervisor_per_device = dynamips_config.get("allocate_hypervisor_per_device", True)
|
||||
self._memory_usage_limit_per_hypervisor = dynamips_config.get("memory_usage_limit_per_hypervisor", 1024)
|
||||
self._allocate_hypervisor_per_ios_image = dynamips_config.get("allocate_hypervisor_per_ios_image", True)
|
||||
|
||||
def __del__(self):
|
||||
"""
|
||||
Shutdowns all started hypervisors
|
||||
"""
|
||||
|
||||
self.stop_all_hypervisors()
|
||||
|
||||
@property
|
||||
def hypervisors(self):
|
||||
"""
|
||||
Returns all hypervisor instances.
|
||||
|
||||
:returns: list of hypervisor instances
|
||||
"""
|
||||
|
||||
return self._hypervisors
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
"""
|
||||
Returns the Dynamips path.
|
||||
|
||||
:returns: path to Dynamips
|
||||
"""
|
||||
|
||||
return self._path
|
||||
|
||||
@path.setter
|
||||
def path(self, path):
|
||||
"""
|
||||
Set a new Dynamips path.
|
||||
|
||||
:param path: path to Dynamips
|
||||
"""
|
||||
|
||||
self._path = path
|
||||
log.info("Dynamips path set to {}".format(self._path))
|
||||
|
||||
@property
|
||||
def working_dir(self):
|
||||
"""
|
||||
Returns the Dynamips working directory path.
|
||||
|
||||
:returns: path to Dynamips working directory
|
||||
"""
|
||||
|
||||
return self._working_dir
|
||||
|
||||
@working_dir.setter
|
||||
def working_dir(self, working_dir):
|
||||
"""
|
||||
Sets a new path to the Dynamips working directory.
|
||||
|
||||
:param working_dir: path to Dynamips working directory
|
||||
"""
|
||||
|
||||
self._working_dir = os.path.join(working_dir, "dynamips")
|
||||
log.info("working directory set to {}".format(self._working_dir))
|
||||
|
||||
# update all existing hypervisors with the new working directory
|
||||
for hypervisor in self._hypervisors:
|
||||
hypervisor.working_dir = self._working_dir
|
||||
|
||||
@property
|
||||
def hypervisor_start_port_range(self):
|
||||
"""
|
||||
Returns the hypervisor start port range value
|
||||
|
||||
:returns: hypervisor start port range value (integer)
|
||||
"""
|
||||
|
||||
return self._hypervisor_start_port_range
|
||||
|
||||
@hypervisor_start_port_range.setter
|
||||
def hypervisor_start_port_range(self, hypervisor_start_port_range):
|
||||
"""
|
||||
Sets a new hypervisor start port range value
|
||||
|
||||
:param hypervisor_start_port_range: hypervisor start port range value (integer)
|
||||
"""
|
||||
|
||||
if self._hypervisor_start_port_range != hypervisor_start_port_range:
|
||||
self._hypervisor_start_port_range = hypervisor_start_port_range
|
||||
log.info("hypervisor start port range value set to {}".format(self._hypervisor_start_port_range))
|
||||
|
||||
@property
|
||||
def hypervisor_end_port_range(self):
|
||||
"""
|
||||
Returns the hypervisor end port range value
|
||||
|
||||
:returns: hypervisor end port range value (integer)
|
||||
"""
|
||||
|
||||
return self._hypervisor_end_port_range
|
||||
|
||||
@hypervisor_end_port_range.setter
|
||||
def hypervisor_end_port_range(self, hypervisor_end_port_range):
|
||||
"""
|
||||
Sets a new hypervisor end port range value
|
||||
|
||||
:param hypervisor_end_port_range: hypervisor end port range value (integer)
|
||||
"""
|
||||
|
||||
if self._hypervisor_end_port_range != hypervisor_end_port_range:
|
||||
self._hypervisor_end_port_range = hypervisor_end_port_range
|
||||
log.info("hypervisor end port range value set to {}".format(self._hypervisor_end_port_range))
|
||||
|
||||
@property
|
||||
def console_start_port_range(self):
|
||||
"""
|
||||
Returns the console start port range value
|
||||
|
||||
:returns: console start port range value (integer)
|
||||
"""
|
||||
|
||||
return self._console_start_port_range
|
||||
|
||||
@console_start_port_range.setter
|
||||
def console_start_port_range(self, console_start_port_range):
|
||||
"""
|
||||
Sets a new console start port range value
|
||||
|
||||
:param console_start_port_range: console start port range value (integer)
|
||||
"""
|
||||
|
||||
if self._console_start_port_range != console_start_port_range:
|
||||
self._console_start_port_range = console_start_port_range
|
||||
log.info("console start port range value set to {}".format(self._console_start_port_range))
|
||||
|
||||
# update all existing hypervisors with the new value
|
||||
for hypervisor in self._hypervisors:
|
||||
hypervisor.console_start_port_range = console_start_port_range
|
||||
|
||||
@property
|
||||
def console_end_port_range(self):
|
||||
"""
|
||||
Returns the console end port range value
|
||||
|
||||
:returns: console end port range value (integer)
|
||||
"""
|
||||
|
||||
return self._console_end_port_range
|
||||
|
||||
@console_end_port_range.setter
|
||||
def console_end_port_range(self, console_end_port_range):
|
||||
"""
|
||||
Sets a new console end port range value
|
||||
|
||||
:param console_end_port_range: console end port range value (integer)
|
||||
"""
|
||||
|
||||
if self._console_end_port_range != console_end_port_range:
|
||||
self._console_end_port_range = console_end_port_range
|
||||
log.info("console end port range value set to {}".format(self._console_end_port_range))
|
||||
|
||||
# update all existing hypervisors with the new value
|
||||
for hypervisor in self._hypervisors:
|
||||
hypervisor.console_end_port_range = console_end_port_range
|
||||
|
||||
@property
|
||||
def aux_start_port_range(self):
|
||||
"""
|
||||
Returns the auxiliary console start port range value
|
||||
|
||||
:returns: auxiliary console start port range value (integer)
|
||||
"""
|
||||
|
||||
return self._aux_start_port_range
|
||||
|
||||
@aux_start_port_range.setter
|
||||
def aux_start_port_range(self, aux_start_port_range):
|
||||
"""
|
||||
Sets a new auxiliary console start port range value
|
||||
|
||||
:param aux_start_port_range: auxiliary console start port range value (integer)
|
||||
"""
|
||||
|
||||
if self._aux_start_port_range != aux_start_port_range:
|
||||
self._aux_start_port_range = aux_start_port_range
|
||||
log.info("auxiliary console start port range value set to {}".format(self._aux_start_port_range))
|
||||
|
||||
# update all existing hypervisors with the new value
|
||||
for hypervisor in self._hypervisors:
|
||||
hypervisor.aux_start_port_range = aux_start_port_range
|
||||
|
||||
@property
|
||||
def aux_end_port_range(self):
|
||||
"""
|
||||
Returns the auxiliary console end port range value
|
||||
|
||||
:returns: auxiliary console end port range value (integer)
|
||||
"""
|
||||
|
||||
return self._aux_end_port_range
|
||||
|
||||
@aux_end_port_range.setter
|
||||
def aux_end_port_range(self, aux_end_port_range):
|
||||
"""
|
||||
Sets a new auxiliary console end port range value
|
||||
|
||||
:param aux_end_port_range: auxiliary console end port range value (integer)
|
||||
"""
|
||||
|
||||
if self._aux_end_port_range != aux_end_port_range:
|
||||
self._aux_end_port_range = aux_end_port_range
|
||||
log.info("auxiliary console end port range value set to {}".format(self._aux_end_port_range))
|
||||
|
||||
# update all existing hypervisors with the new value
|
||||
for hypervisor in self._hypervisors:
|
||||
hypervisor.aux_end_port_range = aux_end_port_range
|
||||
|
||||
@property
|
||||
def udp_start_port_range(self):
|
||||
"""
|
||||
Returns the UDP start port range value
|
||||
|
||||
:returns: UDP start port range value (integer)
|
||||
"""
|
||||
|
||||
return self._udp_start_port_range
|
||||
|
||||
@udp_start_port_range.setter
|
||||
def udp_start_port_range(self, udp_start_port_range):
|
||||
"""
|
||||
Sets a new UDP start port range value
|
||||
|
||||
:param udp_start_port_range: UDP start port range value (integer)
|
||||
"""
|
||||
|
||||
if self._udp_start_port_range != udp_start_port_range:
|
||||
self._udp_start_port_range = udp_start_port_range
|
||||
log.info("UDP start port range value set to {}".format(self._udp_start_port_range))
|
||||
|
||||
# update all existing hypervisors with the new value
|
||||
for hypervisor in self._hypervisors:
|
||||
hypervisor.udp_start_port_range = udp_start_port_range
|
||||
|
||||
@property
|
||||
def udp_end_port_range(self):
|
||||
"""
|
||||
Returns the UDP end port range value
|
||||
|
||||
:returns: UDP end port range value (integer)
|
||||
"""
|
||||
|
||||
return self._udp_end_port_range
|
||||
|
||||
@udp_end_port_range.setter
|
||||
def udp_end_port_range(self, udp_end_port_range):
|
||||
"""
|
||||
Sets a new UDP end port range value
|
||||
|
||||
:param udp_end_port_range: UDP end port range value (integer)
|
||||
"""
|
||||
|
||||
if self._udp_end_port_range != udp_end_port_range:
|
||||
self._udp_end_port_range = udp_end_port_range
|
||||
log.info("UDP end port range value set to {}".format(self._udp_end_port_range))
|
||||
|
||||
# update all existing hypervisors with the new value
|
||||
for hypervisor in self._hypervisors:
|
||||
hypervisor.udp_end_port_range = udp_end_port_range
|
||||
|
||||
@property
|
||||
def ghost_ios_support(self):
|
||||
"""
|
||||
Returns either ghost IOS is activated or not.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._ghost_ios_support
|
||||
|
||||
@ghost_ios_support.setter
|
||||
def ghost_ios_support(self, ghost_ios_support):
|
||||
"""
|
||||
Sets ghost IOS support.
|
||||
|
||||
:param ghost_ios_support: boolean
|
||||
"""
|
||||
|
||||
if self._ghost_ios_support != ghost_ios_support:
|
||||
self._ghost_ios_support = ghost_ios_support
|
||||
if ghost_ios_support:
|
||||
log.info("ghost IOS support enabled")
|
||||
else:
|
||||
log.info("ghost IOS support disabled")
|
||||
|
||||
@property
|
||||
def mmap_support(self):
|
||||
"""
|
||||
Returns either mmap is activated or not.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._mmap_support
|
||||
|
||||
@mmap_support.setter
|
||||
def mmap_support(self, mmap_support):
|
||||
"""
|
||||
Sets mmap support.
|
||||
|
||||
:param mmap_support: boolean
|
||||
"""
|
||||
|
||||
if self._mmap_support != mmap_support:
|
||||
self._mmap_support = mmap_support
|
||||
if mmap_support:
|
||||
log.info("mmap support enabled")
|
||||
else:
|
||||
log.info("mmap support disabled")
|
||||
|
||||
@property
|
||||
def sparse_memory_support(self):
|
||||
"""
|
||||
Returns either sparse memory is activated or not.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._sparse_memory_support
|
||||
|
||||
@sparse_memory_support.setter
|
||||
def sparse_memory_support(self, sparse_memory_support):
|
||||
"""
|
||||
Sets sparse memory support.
|
||||
|
||||
:param sparse_memory_support: boolean
|
||||
"""
|
||||
|
||||
if self._sparse_memory_support != sparse_memory_support:
|
||||
self._sparse_memory_support = sparse_memory_support
|
||||
if sparse_memory_support:
|
||||
log.info("sparse memory support enabled")
|
||||
else:
|
||||
log.info("sparse memory support disabled")
|
||||
|
||||
@property
|
||||
def jit_sharing_support(self):
|
||||
"""
|
||||
Returns either JIT sharing is activated or not.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._jit_sharing_support
|
||||
|
||||
@jit_sharing_support.setter
|
||||
def jit_sharing_support(self, jit_sharing_support):
|
||||
"""
|
||||
Sets JIT sharing support.
|
||||
|
||||
:param jit_sharing_support: boolean
|
||||
"""
|
||||
|
||||
if self._jit_sharing_support != jit_sharing_support:
|
||||
self._jit_sharing_support = jit_sharing_support
|
||||
if jit_sharing_support:
|
||||
log.info("JIT sharing support enabled")
|
||||
else:
|
||||
log.info("JIT sharing support disabled")
|
||||
|
||||
@property
|
||||
def allocate_hypervisor_per_device(self):
|
||||
"""
|
||||
Returns either an hypervisor is created for each device.
|
||||
|
||||
:returns: True or False
|
||||
"""
|
||||
|
||||
return self._allocate_hypervisor_per_device
|
||||
|
||||
@allocate_hypervisor_per_device.setter
|
||||
def allocate_hypervisor_per_device(self, value):
|
||||
"""
|
||||
Sets if an hypervisor is created for each device.
|
||||
|
||||
:param value: True or False
|
||||
"""
|
||||
|
||||
if self._allocate_hypervisor_per_device != value:
|
||||
self._allocate_hypervisor_per_device = value
|
||||
if value:
|
||||
log.info("allocating an hypervisor per device enabled")
|
||||
else:
|
||||
log.info("allocating an hypervisor per device disabled")
|
||||
|
||||
@property
|
||||
def memory_usage_limit_per_hypervisor(self):
|
||||
"""
|
||||
Returns the memory usage limit per hypervisor
|
||||
|
||||
:returns: limit value (integer)
|
||||
"""
|
||||
|
||||
return self._memory_usage_limit_per_hypervisor
|
||||
|
||||
@memory_usage_limit_per_hypervisor.setter
|
||||
def memory_usage_limit_per_hypervisor(self, memory_limit):
|
||||
"""
|
||||
Sets the memory usage limit per hypervisor
|
||||
|
||||
:param memory_limit: memory limit value (integer)
|
||||
"""
|
||||
|
||||
if self._memory_usage_limit_per_hypervisor != memory_limit:
|
||||
self._memory_usage_limit_per_hypervisor = memory_limit
|
||||
log.info("memory usage limit per hypervisor set to {}".format(memory_limit))
|
||||
|
||||
@property
|
||||
def allocate_hypervisor_per_ios_image(self):
|
||||
"""
|
||||
Returns if router are grouped per hypervisor
|
||||
based on their IOS image.
|
||||
|
||||
:returns: True or False
|
||||
"""
|
||||
|
||||
return self._allocate_hypervisor_per_ios_image
|
||||
|
||||
@allocate_hypervisor_per_ios_image.setter
|
||||
def allocate_hypervisor_per_ios_image(self, value):
|
||||
"""
|
||||
Sets if routers are grouped per hypervisor
|
||||
based on their IOS image.
|
||||
|
||||
:param value: True or False
|
||||
"""
|
||||
|
||||
if self._allocate_hypervisor_per_ios_image != value:
|
||||
self._allocate_hypervisor_per_ios_image = value
|
||||
if value:
|
||||
log.info("allocating an hypervisor per IOS image enabled")
|
||||
else:
|
||||
log.info("allocating an hypervisor per IOS image disabled")
|
||||
|
||||
def wait_for_hypervisor(self, host, port):
|
||||
"""
|
||||
Waits for an hypervisor to be started (accepting a socket connection)
|
||||
|
||||
:param host: host/address to connect to the hypervisor
|
||||
:param port: port to connect to the hypervisor
|
||||
"""
|
||||
|
||||
begin = time.time()
|
||||
# wait for the socket for a maximum of 10 seconds.
|
||||
connection_success, last_exception = wait_socket_is_ready(host, port, wait=10.0)
|
||||
|
||||
if not connection_success:
|
||||
# FIXME: throw exception here
|
||||
log.critical("Couldn't connect to hypervisor on {}:{} :{}".format(host, port,
|
||||
last_exception))
|
||||
else:
|
||||
log.info("Dynamips server ready after {:.4f} seconds".format(time.time() - begin))
|
||||
|
||||
def start_new_hypervisor(self):
|
||||
"""
|
||||
Creates a new Dynamips process and start it.
|
||||
|
||||
:returns: the new hypervisor instance
|
||||
"""
|
||||
|
||||
try:
|
||||
port = find_unused_port(self._hypervisor_start_port_range, self._hypervisor_end_port_range, self._host)
|
||||
except Exception as e:
|
||||
raise DynamipsError(e)
|
||||
|
||||
hypervisor = Hypervisor(self._path,
|
||||
self._working_dir,
|
||||
self._host,
|
||||
port)
|
||||
|
||||
log.info("creating new hypervisor {}:{} with working directory {}".format(hypervisor.host, hypervisor.port, self._working_dir))
|
||||
hypervisor.start()
|
||||
|
||||
self.wait_for_hypervisor(self._host, port)
|
||||
log.info("hypervisor {}:{} has successfully started".format(hypervisor.host, hypervisor.port))
|
||||
|
||||
hypervisor.connect()
|
||||
if parse_version(hypervisor.version) < parse_version('0.2.11'):
|
||||
raise DynamipsError("Dynamips version must be >= 0.2.11, detected version is {}".format(hypervisor.version))
|
||||
|
||||
hypervisor.console_start_port_range = self._console_start_port_range
|
||||
hypervisor.console_end_port_range = self._console_end_port_range
|
||||
hypervisor.aux_start_port_range = self._aux_start_port_range
|
||||
hypervisor.aux_end_port_range = self._aux_end_port_range
|
||||
hypervisor.udp_start_port_range = self._udp_start_port_range
|
||||
hypervisor.udp_end_port_range = self._udp_end_port_range
|
||||
self._hypervisors.append(hypervisor)
|
||||
return hypervisor
|
||||
|
||||
def allocate_hypervisor_for_router(self, router_ios_image, router_ram):
|
||||
"""
|
||||
Allocates a Dynamips hypervisor for a specific router
|
||||
(new or existing depending on the RAM amount and IOS image)
|
||||
|
||||
:param router_ios_image: IOS image name
|
||||
:param router_ram: amount of RAM (integer)
|
||||
|
||||
:returns: the allocated hypervisor instance
|
||||
"""
|
||||
|
||||
# allocate an hypervisor for each router by default
|
||||
if not self._allocate_hypervisor_per_device:
|
||||
for hypervisor in self._hypervisors:
|
||||
if self._allocate_hypervisor_per_ios_image:
|
||||
if not hypervisor.image_ref:
|
||||
hypervisor.image_ref = router_ios_image
|
||||
elif hypervisor.image_ref != router_ios_image:
|
||||
continue
|
||||
if (hypervisor.memory_load + router_ram) <= self._memory_usage_limit_per_hypervisor:
|
||||
current_memory_load = hypervisor.memory_load
|
||||
hypervisor.increase_memory_load(router_ram)
|
||||
log.info("allocating existing hypervisor {}:{}, RAM={}+{}".format(hypervisor.host,
|
||||
hypervisor.port,
|
||||
current_memory_load,
|
||||
router_ram))
|
||||
return hypervisor
|
||||
|
||||
hypervisor = self.start_new_hypervisor()
|
||||
hypervisor.image_ref = router_ios_image
|
||||
hypervisor.increase_memory_load(router_ram)
|
||||
return hypervisor
|
||||
|
||||
def unallocate_hypervisor_for_router(self, router):
|
||||
"""
|
||||
Unallocates a Dynamips hypervisor for a specific router.
|
||||
|
||||
:param router: Router instance
|
||||
"""
|
||||
|
||||
hypervisor = router.hypervisor
|
||||
hypervisor.decrease_memory_load(router.ram)
|
||||
|
||||
if hypervisor.memory_load < 0:
|
||||
log.warn("hypervisor {}:{} has a memory load below 0 ({})".format(hypervisor.host,
|
||||
hypervisor.port,
|
||||
hypervisor.memory_load))
|
||||
#hypervisor.memory_load = 0
|
||||
|
||||
# memory load at 0MB and no devices managed anymore...
|
||||
# let's stop this hypervisor
|
||||
if hypervisor.memory_load == 0 and not hypervisor.devices:
|
||||
hypervisor.stop()
|
||||
self._hypervisors.remove(hypervisor)
|
||||
|
||||
def allocate_hypervisor_for_simulated_device(self):
|
||||
"""
|
||||
Allocates a Dynamips hypervisor for a specific Dynamips simulated device.
|
||||
|
||||
:returns: the allocated hypervisor instance
|
||||
"""
|
||||
|
||||
# For now always allocate the first hypervisor available,
|
||||
# in the future we could randomly allocate.
|
||||
|
||||
if self._hypervisors:
|
||||
return self._hypervisors[0]
|
||||
|
||||
# no hypervisor, let's start one!
|
||||
return self.start_new_hypervisor()
|
||||
|
||||
def unallocate_hypervisor_for_simulated_device(self, device):
|
||||
"""
|
||||
Unallocates a Dynamips hypervisor for a specific Dynamips simulated device.
|
||||
|
||||
:param device: device instance
|
||||
"""
|
||||
|
||||
hypervisor = device.hypervisor
|
||||
if not hypervisor.devices:
|
||||
hypervisor.stop()
|
||||
self._hypervisors.remove(hypervisor)
|
||||
|
||||
def stop_all_hypervisors(self):
|
||||
"""
|
||||
Stops all hypervisors.
|
||||
"""
|
||||
|
||||
for hypervisor in self._hypervisors:
|
||||
hypervisor.stop()
|
||||
self._hypervisors = []
|
@ -1,172 +0,0 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Interface for Dynamips virtual ATM bridge module ("atm_bridge").
|
||||
http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L622
|
||||
"""
|
||||
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
|
||||
class ATMBridge(object):
|
||||
|
||||
"""
|
||||
Dynamips bridge switch.
|
||||
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
:param name: name for this switch
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
|
||||
# FIXME: instance tracking
|
||||
self._hypervisor = hypervisor
|
||||
self._name = '"' + name + '"' # put name into quotes to protect spaces
|
||||
self._hypervisor.send("atm_bridge create {}".format(self._name))
|
||||
self._hypervisor.devices.append(self)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Returns the current name of this ATM bridge.
|
||||
|
||||
:returns: ATM bridge name
|
||||
"""
|
||||
|
||||
return self._name[1:-1] # remove quotes
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
"""
|
||||
Renames this ATM bridge.
|
||||
|
||||
:param new_name: New name for this bridge
|
||||
"""
|
||||
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("atm_bridge rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def hypervisor(self):
|
||||
"""
|
||||
Returns the current hypervisor.
|
||||
|
||||
:returns: hypervisor instance
|
||||
"""
|
||||
|
||||
return self._hypervisor
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all ATM bridge instances.
|
||||
|
||||
:returns: list of all ATM bridges
|
||||
"""
|
||||
|
||||
return self._hypervisor.send("atm_bridge list")
|
||||
|
||||
@property
|
||||
def nios(self):
|
||||
"""
|
||||
Returns all the NIOs member of this ATM bridge.
|
||||
|
||||
:returns: nio list
|
||||
"""
|
||||
|
||||
return self._nios
|
||||
|
||||
@property
|
||||
def mapping(self):
|
||||
"""
|
||||
Returns port mapping
|
||||
|
||||
:returns: mapping list
|
||||
"""
|
||||
|
||||
return self._mapping
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this ATM bridge.
|
||||
"""
|
||||
|
||||
self._hypervisor.send("atm_bridge delete {}".format(self._name))
|
||||
self._hypervisor.devices.remove(self)
|
||||
|
||||
def add_nio(self, nio, port):
|
||||
"""
|
||||
Adds a NIO as new port on ATM bridge.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
:param port: port to allocate for the NIO
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
raise DynamipsError("Port {} isn't free".format(port))
|
||||
|
||||
self._nios[port] = nio
|
||||
|
||||
def remove_nio(self, port):
|
||||
"""
|
||||
Removes the specified NIO as member of this ATM switch.
|
||||
|
||||
:param port: allocated port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
del self._nios[port]
|
||||
|
||||
def configure(self, eth_port, atm_port, atm_vpi, atm_vci):
|
||||
"""
|
||||
Configures this ATM bridge.
|
||||
|
||||
:param eth_port: Ethernet port
|
||||
:param atm_port: ATM port
|
||||
:param atm_vpi: ATM VPI
|
||||
:param atm_vci: ATM VCI
|
||||
"""
|
||||
|
||||
if eth_port not in self._nios:
|
||||
raise DynamipsError("Ethernet port {} is not allocated".format(eth_port))
|
||||
|
||||
if atm_port not in self._nios:
|
||||
raise DynamipsError("ATM port {} is not allocated".format(atm_port))
|
||||
|
||||
eth_nio = self._nios[eth_port]
|
||||
atm_nio = self._nios[atm_port]
|
||||
|
||||
self._hypervisor.send("atm_bridge configure {name} {eth_nio} {atm_nio} {vpi} {vci}".format(name=self._name,
|
||||
eth_nio=eth_nio,
|
||||
atm_nio=atm_nio,
|
||||
vpi=atm_vpi,
|
||||
vci=atm_vci))
|
||||
self._mapping[eth_port] = (atm_port, atm_vpi, atm_vci)
|
||||
|
||||
def unconfigure(self):
|
||||
"""
|
||||
Unconfigures this ATM bridge.
|
||||
"""
|
||||
|
||||
self._hypervisor.send("atm_bridge unconfigure {}".format(self._name))
|
||||
del self._mapping
|
@ -1,406 +0,0 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Interface for Dynamips virtual ATM switch module ("atmsw").
|
||||
http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L593
|
||||
"""
|
||||
|
||||
import os
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ATMSwitch(object):
|
||||
|
||||
"""
|
||||
Dynamips ATM switch.
|
||||
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
:param name: name for this switch
|
||||
"""
|
||||
|
||||
_instances = []
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
|
||||
# find an instance identifier (0 < id <= 4096)
|
||||
self._id = 0
|
||||
for identifier in range(1, 4097):
|
||||
if identifier not in self._instances:
|
||||
self._id = identifier
|
||||
self._instances.append(self._id)
|
||||
break
|
||||
|
||||
if self._id == 0:
|
||||
raise DynamipsError("Maximum number of instances reached")
|
||||
|
||||
self._hypervisor = hypervisor
|
||||
self._name = '"' + name + '"' # put name into quotes to protect spaces
|
||||
self._hypervisor.send("atmsw create {}".format(self._name))
|
||||
|
||||
log.info("ATM switch {name} [id={id}] has been created".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
self._hypervisor.devices.append(self)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Resets the instance count and the allocated instances list.
|
||||
"""
|
||||
|
||||
cls._instances.clear()
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Returns the unique ID for this ATM switch.
|
||||
|
||||
:returns: id (integer)
|
||||
"""
|
||||
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Returns the current name of this ATM switch.
|
||||
|
||||
:returns: ATM switch name
|
||||
"""
|
||||
|
||||
return self._name[1:-1] # remove quotes
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
"""
|
||||
Renames this ATM switch.
|
||||
|
||||
:param new_name: New name for this switch
|
||||
"""
|
||||
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("atmsw rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: renamed to {new_name}".format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def hypervisor(self):
|
||||
"""
|
||||
Returns the current hypervisor.
|
||||
|
||||
:returns: hypervisor instance
|
||||
"""
|
||||
|
||||
return self._hypervisor
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all ATM switches instances.
|
||||
|
||||
:returns: list of all ATM switches
|
||||
"""
|
||||
|
||||
return self._hypervisor.send("atmsw list")
|
||||
|
||||
@property
|
||||
def nios(self):
|
||||
"""
|
||||
Returns all the NIOs member of this ATM switch.
|
||||
|
||||
:returns: nio list
|
||||
"""
|
||||
|
||||
return self._nios
|
||||
|
||||
@property
|
||||
def mapping(self):
|
||||
"""
|
||||
Returns port mapping
|
||||
|
||||
:returns: mapping list
|
||||
"""
|
||||
|
||||
return self._mapping
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this ATM switch.
|
||||
"""
|
||||
|
||||
self._hypervisor.send("atmsw delete {}".format(self._name))
|
||||
|
||||
log.info("ATM switch {name} [id={id}] has been deleted".format(name=self._name,
|
||||
id=self._id))
|
||||
self._hypervisor.devices.remove(self)
|
||||
self._instances.remove(self._id)
|
||||
|
||||
def has_port(self, port):
|
||||
"""
|
||||
Checks if a port exists on this ATM switch.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_nio(self, nio, port):
|
||||
"""
|
||||
Adds a NIO as new port on ATM switch.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
:param port: port to allocate for the NIO
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
raise DynamipsError("Port {} isn't free".format(port))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: NIO {nio} bound to port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
self._nios[port] = nio
|
||||
|
||||
def remove_nio(self, port):
|
||||
"""
|
||||
Removes the specified NIO as member of this ATM switch.
|
||||
|
||||
:param port: allocated port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
log.info("ATM switch {name} [id={id}]: NIO {nio} removed from port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
del self._nios[port]
|
||||
return nio
|
||||
|
||||
def map_vp(self, port1, vpi1, port2, vpi2):
|
||||
"""
|
||||
Creates a new Virtual Path connection.
|
||||
|
||||
:param port1: input port
|
||||
:param vpi1: input vpi
|
||||
:param port2: output port
|
||||
:param vpi2: output vpi
|
||||
"""
|
||||
|
||||
if port1 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port1))
|
||||
|
||||
if port2 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port2))
|
||||
|
||||
nio1 = self._nios[port1]
|
||||
nio2 = self._nios[port2]
|
||||
|
||||
self._hypervisor.send("atmsw create_vpc {name} {input_nio} {input_vpi} {output_nio} {output_vpi}".format(name=self._name,
|
||||
input_nio=nio1,
|
||||
input_vpi=vpi1,
|
||||
output_nio=nio2,
|
||||
output_vpi=vpi2))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: VPC from port {port1} VPI {vpi1} to port {port2} VPI {vpi2} created".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
port2=port2,
|
||||
vpi2=vpi2))
|
||||
|
||||
self._mapping[(port1, vpi1)] = (port2, vpi2)
|
||||
|
||||
def unmap_vp(self, port1, vpi1, port2, vpi2):
|
||||
"""
|
||||
Deletes a new Virtual Path connection.
|
||||
|
||||
:param port1: input port
|
||||
:param vpi1: input vpi
|
||||
:param port2: output port
|
||||
:param vpi2: output vpi
|
||||
"""
|
||||
|
||||
if port1 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port1))
|
||||
|
||||
if port2 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port2))
|
||||
|
||||
nio1 = self._nios[port1]
|
||||
nio2 = self._nios[port2]
|
||||
|
||||
self._hypervisor.send("atmsw delete_vpc {name} {input_nio} {input_vpi} {output_nio} {output_vpi}".format(name=self._name,
|
||||
input_nio=nio1,
|
||||
input_vpi=vpi1,
|
||||
output_nio=nio2,
|
||||
output_vpi=vpi2))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: VPC from port {port1} VPI {vpi1} to port {port2} VPI {vpi2} deleted".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
port2=port2,
|
||||
vpi2=vpi2))
|
||||
|
||||
del self._mapping[(port1, vpi1)]
|
||||
|
||||
def map_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2):
|
||||
"""
|
||||
Creates a new Virtual Channel connection (unidirectional).
|
||||
|
||||
:param port1: input port
|
||||
:param vpi1: input vpi
|
||||
:param vci1: input vci
|
||||
:param port2: output port
|
||||
:param vpi2: output vpi
|
||||
:param vci2: output vci
|
||||
"""
|
||||
|
||||
if port1 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port1))
|
||||
|
||||
if port2 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port2))
|
||||
|
||||
nio1 = self._nios[port1]
|
||||
nio2 = self._nios[port2]
|
||||
|
||||
self._hypervisor.send("atmsw create_vcc {name} {input_nio} {input_vpi} {input_vci} {output_nio} {output_vpi} {output_vci}".format(name=self._name,
|
||||
input_nio=nio1,
|
||||
input_vpi=vpi1,
|
||||
input_vci=vci1,
|
||||
output_nio=nio2,
|
||||
output_vpi=vpi2,
|
||||
output_vci=vci2))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: VCC from port {port1} VPI {vpi1} VCI {vci1} to port {port2} VPI {vpi2} VCI {vci2} created".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
vci1=vci1,
|
||||
port2=port2,
|
||||
vpi2=vpi2,
|
||||
vci2=vci2))
|
||||
|
||||
self._mapping[(port1, vpi1, vci1)] = (port2, vpi2, vci2)
|
||||
|
||||
def unmap_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2):
|
||||
"""
|
||||
Deletes a new Virtual Channel connection (unidirectional).
|
||||
|
||||
:param port1: input port
|
||||
:param vpi1: input vpi
|
||||
:param vci1: input vci
|
||||
:param port2: output port
|
||||
:param vpi2: output vpi
|
||||
:param vci2: output vci
|
||||
"""
|
||||
|
||||
if port1 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port1))
|
||||
|
||||
if port2 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port2))
|
||||
|
||||
nio1 = self._nios[port1]
|
||||
nio2 = self._nios[port2]
|
||||
|
||||
self._hypervisor.send("atmsw delete_vcc {name} {input_nio} {input_vpi} {input_vci} {output_nio} {output_vpi} {output_vci}".format(name=self._name,
|
||||
input_nio=nio1,
|
||||
input_vpi=vpi1,
|
||||
input_vci=vci1,
|
||||
output_nio=nio2,
|
||||
output_vpi=vpi2,
|
||||
output_vci=vci2))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: VCC from port {port1} VPI {vpi1} VCI {vci1} to port {port2} VPI {vpi2} VCI {vci2} deleted".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
vci1=vci1,
|
||||
port2=port2,
|
||||
vpi2=vpi2,
|
||||
vci2=vci2))
|
||||
del self._mapping[(port1, vpi1, vci1)]
|
||||
|
||||
def start_capture(self, port, output_file, data_link_type="DLT_ATM_RFC1483"):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
:param port: allocated port
|
||||
:param output_file: PCAP destination file for the capture
|
||||
:param data_link_type: PCAP data link type (DLT_*), default is DLT_ATM_RFC1483
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
|
||||
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))
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not create captures directory {}".format(e))
|
||||
|
||||
nio.bind_filter("both", "capture")
|
||||
nio.setup_filter("both", "{} {}".format(data_link_type, output_file))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: starting packet capture on {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port))
|
||||
|
||||
def stop_capture(self, port):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
:param port: allocated port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
nio.unbind_filter("both")
|
||||
log.info("ATM switch {name} [id={id}]: stopping packet capture on {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port))
|
@ -1,122 +0,0 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Interface for Dynamips NIO bridge module ("nio_bridge").
|
||||
http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L538
|
||||
"""
|
||||
|
||||
|
||||
class Bridge(object):
|
||||
|
||||
"""
|
||||
Dynamips bridge.
|
||||
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
:param name: name for this bridge
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
|
||||
self._hypervisor = hypervisor
|
||||
self._name = '"' + name + '"' # put name into quotes to protect spaces
|
||||
self._hypervisor.send("nio_bridge create {}".format(self._name))
|
||||
self._hypervisor.devices.append(self)
|
||||
self._nios = []
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Returns the current name of this bridge.
|
||||
|
||||
:returns: bridge name
|
||||
"""
|
||||
|
||||
return self._name[1:-1] # remove quotes
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
"""
|
||||
Renames this bridge.
|
||||
|
||||
:param new_name: New name for this bridge
|
||||
"""
|
||||
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("nio_bridge rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def hypervisor(self):
|
||||
"""
|
||||
Returns the current hypervisor.
|
||||
|
||||
:returns: hypervisor instance
|
||||
"""
|
||||
|
||||
return self._hypervisor
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all bridge instances.
|
||||
|
||||
:returns: list of all bridges
|
||||
"""
|
||||
|
||||
return self._hypervisor.send("nio_bridge list")
|
||||
|
||||
@property
|
||||
def nios(self):
|
||||
"""
|
||||
Returns all the NIOs member of this bridge.
|
||||
|
||||
:returns: nio list
|
||||
"""
|
||||
|
||||
return self._nios
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this bridge.
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio_bridge delete {}".format(self._name))
|
||||
self._hypervisor.devices.remove(self)
|
||||
|
||||
def add_nio(self, nio):
|
||||
"""
|
||||
Adds a NIO as new port on this bridge.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio_bridge add_nio {name} {nio}".format(name=self._name,
|
||||
nio=nio))
|
||||
self._nios.append(nio)
|
||||
|
||||
def remove_nio(self, nio):
|
||||
"""
|
||||
Removes the specified NIO as member of this bridge.
|
||||
|
||||
:param nio: NIO instance to remove
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio_bridge remove_nio {name} {nio}".format(name=self._name,
|
||||
nio=nio))
|
||||
self._nios.remove(nio)
|
@ -1,342 +0,0 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Interface for Dynamips virtual Ethernet switch module ("ethsw").
|
||||
http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L558
|
||||
"""
|
||||
|
||||
import os
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EthernetSwitch(object):
|
||||
|
||||
"""
|
||||
Dynamips Ethernet switch.
|
||||
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
:param name: name for this switch
|
||||
"""
|
||||
|
||||
_instances = []
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
|
||||
# find an instance identifier (0 < id <= 4096)
|
||||
self._id = 0
|
||||
for identifier in range(1, 4097):
|
||||
if identifier not in self._instances:
|
||||
self._id = identifier
|
||||
self._instances.append(self._id)
|
||||
break
|
||||
|
||||
if self._id == 0:
|
||||
raise DynamipsError("Maximum number of instances reached")
|
||||
|
||||
self._hypervisor = hypervisor
|
||||
self._name = '"' + name + '"' # put name into quotes to protect spaces
|
||||
self._hypervisor.send("ethsw create {}".format(self._name))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}] has been created".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
self._hypervisor.devices.append(self)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Resets the instance count and the allocated instances list.
|
||||
"""
|
||||
|
||||
cls._instances.clear()
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Returns the unique ID for this Ethernet switch.
|
||||
|
||||
:returns: id (integer)
|
||||
"""
|
||||
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Returns the current name of this Ethernet switch.
|
||||
|
||||
:returns: Ethernet switch name
|
||||
"""
|
||||
|
||||
return self._name[1:-1] # remove quotes
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
"""
|
||||
Renames this Ethernet switch.
|
||||
|
||||
:param new_name: New name for this switch
|
||||
"""
|
||||
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("ethsw rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: renamed to {new_name}".format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def hypervisor(self):
|
||||
"""
|
||||
Returns the current hypervisor.
|
||||
|
||||
:returns: hypervisor instance
|
||||
"""
|
||||
|
||||
return self._hypervisor
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all Ethernet switches instances.
|
||||
|
||||
:returns: list of all Ethernet switches
|
||||
"""
|
||||
|
||||
return self._hypervisor.send("ethsw list")
|
||||
|
||||
@property
|
||||
def nios(self):
|
||||
"""
|
||||
Returns all the NIOs member of this Ethernet switch.
|
||||
|
||||
:returns: nio list
|
||||
"""
|
||||
|
||||
return self._nios
|
||||
|
||||
@property
|
||||
def mapping(self):
|
||||
"""
|
||||
Returns port mapping
|
||||
|
||||
:returns: mapping list
|
||||
"""
|
||||
|
||||
return self._mapping
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this Ethernet switch.
|
||||
"""
|
||||
|
||||
self._hypervisor.send("ethsw delete {}".format(self._name))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}] has been deleted".format(name=self._name,
|
||||
id=self._id))
|
||||
self._hypervisor.devices.remove(self)
|
||||
self._instances.remove(self._id)
|
||||
|
||||
def add_nio(self, nio, port):
|
||||
"""
|
||||
Adds a NIO as new port on Ethernet switch.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
:param port: port to allocate for the NIO
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
raise DynamipsError("Port {} isn't free".format(port))
|
||||
|
||||
self._hypervisor.send("ethsw add_nio {name} {nio}".format(name=self._name,
|
||||
nio=nio))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: NIO {nio} bound to port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
self._nios[port] = nio
|
||||
|
||||
def remove_nio(self, port):
|
||||
"""
|
||||
Removes the specified NIO as member of this Ethernet switch.
|
||||
|
||||
:param port: allocated port
|
||||
|
||||
:returns: the NIO that was bound to the port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
self._hypervisor.send("ethsw remove_nio {name} {nio}".format(name=self._name,
|
||||
nio=nio))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: NIO {nio} removed from port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
del self._nios[port]
|
||||
|
||||
if port in self._mapping:
|
||||
del self._mapping[port]
|
||||
|
||||
return nio
|
||||
|
||||
def set_access_port(self, port, vlan_id):
|
||||
"""
|
||||
Sets the specified port as an ACCESS port.
|
||||
|
||||
:param port: allocated port
|
||||
:param vlan_id: VLAN number membership
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
self._hypervisor.send("ethsw set_access_port {name} {nio} {vlan_id}".format(name=self._name,
|
||||
nio=nio,
|
||||
vlan_id=vlan_id))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: port {port} set as an access port in VLAN {vlan_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port,
|
||||
vlan_id=vlan_id))
|
||||
self._mapping[port] = ("access", vlan_id)
|
||||
|
||||
def set_dot1q_port(self, port, native_vlan):
|
||||
"""
|
||||
Sets the specified port as a 802.1Q trunk port.
|
||||
|
||||
:param port: allocated port
|
||||
:param native_vlan: native VLAN for this trunk port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
self._hypervisor.send("ethsw set_dot1q_port {name} {nio} {native_vlan}".format(name=self._name,
|
||||
nio=nio,
|
||||
native_vlan=native_vlan))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: port {port} set as a 802.1Q port with native VLAN {vlan_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port,
|
||||
vlan_id=native_vlan))
|
||||
|
||||
self._mapping[port] = ("dot1q", native_vlan)
|
||||
|
||||
def set_qinq_port(self, port, outer_vlan):
|
||||
"""
|
||||
Sets the specified port as a trunk (QinQ) port.
|
||||
|
||||
:param port: allocated port
|
||||
:param outer_vlan: outer VLAN (transport VLAN) for this QinQ port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
self._hypervisor.send("ethsw set_qinq_port {name} {nio} {outer_vlan}".format(name=self._name,
|
||||
nio=nio,
|
||||
outer_vlan=outer_vlan))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: port {port} set as a QinQ port with outer VLAN {vlan_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port,
|
||||
vlan_id=outer_vlan))
|
||||
self._mapping[port] = ("qinq", outer_vlan)
|
||||
|
||||
def get_mac_addr_table(self):
|
||||
"""
|
||||
Returns the MAC address table for this Ethernet switch.
|
||||
|
||||
:returns: list of entries (Ethernet address, VLAN, NIO)
|
||||
"""
|
||||
|
||||
return self._hypervisor.send("ethsw show_mac_addr_table {}".format(self._name))
|
||||
|
||||
def clear_mac_addr_table(self):
|
||||
"""
|
||||
Clears the MAC address table for this Ethernet switch.
|
||||
"""
|
||||
|
||||
self._hypervisor.send("ethsw clear_mac_addr_table {}".format(self._name))
|
||||
|
||||
def start_capture(self, port, output_file, data_link_type="DLT_EN10MB"):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
:param port: allocated port
|
||||
:param output_file: PCAP destination file for the capture
|
||||
:param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
|
||||
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))
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not create captures directory {}".format(e))
|
||||
|
||||
nio.bind_filter("both", "capture")
|
||||
nio.setup_filter("both", "{} {}".format(data_link_type, output_file))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: starting packet capture on {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port))
|
||||
|
||||
def stop_capture(self, port):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
:param port: allocated port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
nio.unbind_filter("both")
|
||||
log.info("Ethernet switch {name} [id={id}]: stopping packet capture on {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port))
|
@ -1,328 +0,0 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Interface for Dynamips virtual Frame-Relay switch module.
|
||||
http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L642
|
||||
"""
|
||||
|
||||
import os
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FrameRelaySwitch(object):
|
||||
|
||||
"""
|
||||
Dynamips Frame Relay switch.
|
||||
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
:param name: name for this switch
|
||||
"""
|
||||
|
||||
_instances = []
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
|
||||
# find an instance identifier (0 < id <= 4096)
|
||||
self._id = 0
|
||||
for identifier in range(1, 4097):
|
||||
if identifier not in self._instances:
|
||||
self._id = identifier
|
||||
self._instances.append(self._id)
|
||||
break
|
||||
|
||||
if self._id == 0:
|
||||
raise DynamipsError("Maximum number of instances reached")
|
||||
|
||||
self._hypervisor = hypervisor
|
||||
self._name = '"' + name + '"' # put name into quotes to protect spaces
|
||||
self._hypervisor.send("frsw create {}".format(self._name))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}] has been created".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
self._hypervisor.devices.append(self)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Resets the instance count and the allocated instances list.
|
||||
"""
|
||||
|
||||
cls._instances.clear()
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Returns the unique ID for this Frame Relay switch.
|
||||
|
||||
:returns: id (integer)
|
||||
"""
|
||||
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Returns the current name of this Frame Relay switch.
|
||||
|
||||
:returns: Frame Relay switch name
|
||||
"""
|
||||
|
||||
return self._name[1:-1] # remove quotes
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
"""
|
||||
Renames this Frame Relay switch.
|
||||
|
||||
:param new_name: New name for this switch
|
||||
"""
|
||||
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("frsw rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}]: renamed to {new_name}".format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def hypervisor(self):
|
||||
"""
|
||||
Returns the current hypervisor.
|
||||
|
||||
:returns: hypervisor instance
|
||||
"""
|
||||
|
||||
return self._hypervisor
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all Frame Relay switches instances.
|
||||
|
||||
:returns: list of all Frame Relay switches
|
||||
"""
|
||||
|
||||
return self._hypervisor.send("frsw list")
|
||||
|
||||
@property
|
||||
def nios(self):
|
||||
"""
|
||||
Returns all the NIOs member of this Frame Relay switch.
|
||||
|
||||
:returns: nio list
|
||||
"""
|
||||
|
||||
return self._nios
|
||||
|
||||
@property
|
||||
def mapping(self):
|
||||
"""
|
||||
Returns port mapping
|
||||
|
||||
:returns: mapping list
|
||||
"""
|
||||
|
||||
return self._mapping
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this Frame Relay switch.
|
||||
"""
|
||||
|
||||
self._hypervisor.send("frsw delete {}".format(self._name))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}] has been deleted".format(name=self._name,
|
||||
id=self._id))
|
||||
self._hypervisor.devices.remove(self)
|
||||
self._instances.remove(self._id)
|
||||
|
||||
def has_port(self, port):
|
||||
"""
|
||||
Checks if a port exists on this Frame Relay switch.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_nio(self, nio, port):
|
||||
"""
|
||||
Adds a NIO as new port on Frame Relay switch.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
:param port: port to allocate for the NIO
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
raise DynamipsError("Port {} isn't free".format(port))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}]: NIO {nio} bound to port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
self._nios[port] = nio
|
||||
|
||||
def remove_nio(self, port):
|
||||
"""
|
||||
Removes the specified NIO as member of this Frame Relay switch.
|
||||
|
||||
:param port: allocated port
|
||||
|
||||
:returns: the NIO that was bound to the allocated port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
log.info("Frame Relay switch {name} [id={id}]: NIO {nio} removed from port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
del self._nios[port]
|
||||
return nio
|
||||
|
||||
def map_vc(self, port1, dlci1, port2, dlci2):
|
||||
"""
|
||||
Creates a new Virtual Circuit connection (unidirectional).
|
||||
|
||||
:param port1: input port
|
||||
:param dlci1: input DLCI
|
||||
:param port2: output port
|
||||
:param dlci2: output DLCI
|
||||
"""
|
||||
|
||||
if port1 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port1))
|
||||
|
||||
if port2 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port2))
|
||||
|
||||
nio1 = self._nios[port1]
|
||||
nio2 = self._nios[port2]
|
||||
|
||||
self._hypervisor.send("frsw create_vc {name} {input_nio} {input_dlci} {output_nio} {output_dlci}".format(name=self._name,
|
||||
input_nio=nio1,
|
||||
input_dlci=dlci1,
|
||||
output_nio=nio2,
|
||||
output_dlci=dlci2))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}]: VC from port {port1} DLCI {dlci1} to port {port2} DLCI {dlci2} created".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
dlci1=dlci1,
|
||||
port2=port2,
|
||||
dlci2=dlci2))
|
||||
|
||||
self._mapping[(port1, dlci1)] = (port2, dlci2)
|
||||
|
||||
def unmap_vc(self, port1, dlci1, port2, dlci2):
|
||||
"""
|
||||
Deletes a Virtual Circuit connection (unidirectional).
|
||||
|
||||
:param port1: input port
|
||||
:param dlci1: input DLCI
|
||||
:param port2: output port
|
||||
:param dlci2: output DLCI
|
||||
"""
|
||||
|
||||
if port1 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port1))
|
||||
|
||||
if port2 not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port2))
|
||||
|
||||
nio1 = self._nios[port1]
|
||||
nio2 = self._nios[port2]
|
||||
|
||||
self._hypervisor.send("frsw delete_vc {name} {input_nio} {input_dlci} {output_nio} {output_dlci}".format(name=self._name,
|
||||
input_nio=nio1,
|
||||
input_dlci=dlci1,
|
||||
output_nio=nio2,
|
||||
output_dlci=dlci2))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}]: VC from port {port1} DLCI {dlci1} to port {port2} DLCI {dlci2} deleted".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
dlci1=dlci1,
|
||||
port2=port2,
|
||||
dlci2=dlci2))
|
||||
del self._mapping[(port1, dlci1)]
|
||||
|
||||
def start_capture(self, port, output_file, data_link_type="DLT_FRELAY"):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
:param port: allocated port
|
||||
:param output_file: PCAP destination file for the capture
|
||||
:param data_link_type: PCAP data link type (DLT_*), default is DLT_FRELAY
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
|
||||
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))
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not create captures directory {}".format(e))
|
||||
|
||||
nio.bind_filter("both", "capture")
|
||||
nio.setup_filter("both", "{} {}".format(data_link_type, output_file))
|
||||
|
||||
log.info("Frame relay switch {name} [id={id}]: starting packet capture on {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port))
|
||||
|
||||
def stop_capture(self, port):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
:param port: allocated port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
nio.unbind_filter("both")
|
||||
log.info("Frame relay switch {name} [id={id}]: stopping packet capture on {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port))
|
@ -1,189 +0,0 @@
|
||||
# -*- 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 os
|
||||
from .bridge import Bridge
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Hub(Bridge):
|
||||
|
||||
"""
|
||||
Dynamips hub (based on Bridge)
|
||||
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
:param name: name for this hub
|
||||
"""
|
||||
|
||||
_instances = []
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
|
||||
# find an instance identifier (0 < id <= 4096)
|
||||
self._id = 0
|
||||
for identifier in range(1, 4097):
|
||||
if identifier not in self._instances:
|
||||
self._id = identifier
|
||||
self._instances.append(self._id)
|
||||
break
|
||||
|
||||
if self._id == 0:
|
||||
raise DynamipsError("Maximum number of instances reached")
|
||||
|
||||
self._mapping = {}
|
||||
Bridge.__init__(self, hypervisor, name)
|
||||
|
||||
log.info("Ethernet hub {name} [id={id}] has been created".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Resets the instance count and the allocated instances list.
|
||||
"""
|
||||
|
||||
cls._instances.clear()
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Returns the unique ID for this Ethernet switch.
|
||||
|
||||
:returns: id (integer)
|
||||
"""
|
||||
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def mapping(self):
|
||||
"""
|
||||
Returns port mapping
|
||||
|
||||
:returns: mapping list
|
||||
"""
|
||||
|
||||
return self._mapping
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this hub.
|
||||
"""
|
||||
|
||||
Bridge.delete(self)
|
||||
log.info("Ethernet hub {name} [id={id}] has been deleted".format(name=self._name,
|
||||
id=self._id))
|
||||
self._instances.remove(self._id)
|
||||
|
||||
def add_nio(self, nio, port):
|
||||
"""
|
||||
Adds a NIO as new port on this hub.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
:param port: port to allocate for the NIO
|
||||
"""
|
||||
|
||||
if port in self._mapping:
|
||||
raise DynamipsError("Port {} isn't free".format(port))
|
||||
|
||||
Bridge.add_nio(self, nio)
|
||||
|
||||
log.info("Ethernet hub {name} [id={id}]: NIO {nio} bound to port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
self._mapping[port] = nio
|
||||
|
||||
def remove_nio(self, port):
|
||||
"""
|
||||
Removes the specified NIO as member of this hub.
|
||||
|
||||
:param port: allocated port
|
||||
|
||||
:returns: the NIO that was bound to the allocated port
|
||||
"""
|
||||
|
||||
if port not in self._mapping:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._mapping[port]
|
||||
Bridge.remove_nio(self, nio)
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: NIO {nio} removed from port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
del self._mapping[port]
|
||||
return nio
|
||||
|
||||
def start_capture(self, port, output_file, data_link_type="DLT_EN10MB"):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
:param port: allocated port
|
||||
:param output_file: PCAP destination file for the capture
|
||||
:param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB
|
||||
"""
|
||||
|
||||
if port not in self._mapping:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._mapping[port]
|
||||
|
||||
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))
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.dirname(output_file))
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not create captures directory {}".format(e))
|
||||
|
||||
nio.bind_filter("both", "capture")
|
||||
nio.setup_filter("both", "{} {}".format(data_link_type, output_file))
|
||||
|
||||
log.info("Ethernet hub {name} [id={id}]: starting packet capture on {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port))
|
||||
|
||||
def stop_capture(self, port):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
:param port: allocated port
|
||||
"""
|
||||
|
||||
if port not in self._mapping:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._mapping[port]
|
||||
nio.unbind_filter("both")
|
||||
log.info("Ethernet hub {name} [id={id}]: stopping packet capture on {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port))
|
File diff suppressed because it is too large
Load Diff
@ -1,322 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
ATMSW_CREATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to create a new ATM switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "ATM switch name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name"]
|
||||
}
|
||||
|
||||
ATMSW_DELETE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete an ATM switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "ATM switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
ATMSW_UPDATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to update an ATM switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "ATM switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"description": "ATM switch name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
ATMSW_ALLOCATE_UDP_PORT_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to allocate an UDP port for an ATM switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "ATM switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the ATM switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id"]
|
||||
}
|
||||
|
||||
ATMSW_ADD_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to add a NIO for an ATM switch instance",
|
||||
"type": "object",
|
||||
|
||||
"definitions": {
|
||||
"UDP": {
|
||||
"description": "UDP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_udp"]
|
||||
},
|
||||
"lport": {
|
||||
"description": "Local port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"rhost": {
|
||||
"description": "Remote host",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"rport": {
|
||||
"description": "Remote port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
}
|
||||
},
|
||||
"required": ["type", "lport", "rhost", "rport"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"Ethernet": {
|
||||
"description": "Generic Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_generic_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"LinuxEthernet": {
|
||||
"description": "Linux Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_linux_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"TAP": {
|
||||
"description": "TAP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_tap"]
|
||||
},
|
||||
"tap_device": {
|
||||
"description": "TAP device name e.g. tap0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "tap_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"UNIX": {
|
||||
"description": "UNIX Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_unix"]
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the UNIX socket file (local)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"remote_file": {
|
||||
"description": "path to the UNIX socket file (remote)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "local_file", "remote_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"VDE": {
|
||||
"description": "VDE Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_vde"]
|
||||
},
|
||||
"control_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "control_file", "local_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"NULL": {
|
||||
"description": "NULL Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_null"]
|
||||
},
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
},
|
||||
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "ATM switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the ATM switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"mappings": {
|
||||
"type": "object",
|
||||
},
|
||||
"nio": {
|
||||
"type": "object",
|
||||
"description": "Network Input/Output",
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/UDP"},
|
||||
{"$ref": "#/definitions/Ethernet"},
|
||||
{"$ref": "#/definitions/LinuxEthernet"},
|
||||
{"$ref": "#/definitions/TAP"},
|
||||
{"$ref": "#/definitions/UNIX"},
|
||||
{"$ref": "#/definitions/VDE"},
|
||||
{"$ref": "#/definitions/NULL"},
|
||||
]
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port", "port_id", "mappings", "nio"],
|
||||
}
|
||||
|
||||
ATMSW_DELETE_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete a NIO for an ATM switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "ATM switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port"]
|
||||
}
|
||||
|
||||
ATMSW_START_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to start a packet capture on an ATM switch instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "ATM switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the ATM switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"capture_file_name": {
|
||||
"description": "Capture file name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"data_link_type": {
|
||||
"description": "PCAP data link type",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port", "capture_file_name"]
|
||||
}
|
||||
|
||||
ATMSW_STOP_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to stop a packet capture on an ATM switch instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "ATM switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the ATM switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port"]
|
||||
}
|
@ -1,319 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
ETHHUB_CREATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to create a new Ethernet hub instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Ethernet hub name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name"]
|
||||
}
|
||||
|
||||
ETHHUB_DELETE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete an Ethernet hub instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
ETHHUB_UPDATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to update an Ethernet hub instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"description": "Ethernet hub name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
ETHHUB_ALLOCATE_UDP_PORT_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to allocate an UDP port for an Ethernet hub instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet hub instance",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id"]
|
||||
}
|
||||
|
||||
ETHHUB_ADD_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to add a NIO for an Ethernet hub instance",
|
||||
"type": "object",
|
||||
|
||||
"definitions": {
|
||||
"UDP": {
|
||||
"description": "UDP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_udp"]
|
||||
},
|
||||
"lport": {
|
||||
"description": "Local port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"rhost": {
|
||||
"description": "Remote host",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"rport": {
|
||||
"description": "Remote port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
}
|
||||
},
|
||||
"required": ["type", "lport", "rhost", "rport"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"Ethernet": {
|
||||
"description": "Generic Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_generic_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"LinuxEthernet": {
|
||||
"description": "Linux Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_linux_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"TAP": {
|
||||
"description": "TAP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_tap"]
|
||||
},
|
||||
"tap_device": {
|
||||
"description": "TAP device name e.g. tap0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "tap_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"UNIX": {
|
||||
"description": "UNIX Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_unix"]
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the UNIX socket file (local)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"remote_file": {
|
||||
"description": "path to the UNIX socket file (remote)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "local_file", "remote_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"VDE": {
|
||||
"description": "VDE Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_vde"]
|
||||
},
|
||||
"control_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "control_file", "local_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"NULL": {
|
||||
"description": "NULL Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_null"]
|
||||
},
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
},
|
||||
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet hub instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"nio": {
|
||||
"type": "object",
|
||||
"description": "Network Input/Output",
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/UDP"},
|
||||
{"$ref": "#/definitions/Ethernet"},
|
||||
{"$ref": "#/definitions/LinuxEthernet"},
|
||||
{"$ref": "#/definitions/TAP"},
|
||||
{"$ref": "#/definitions/UNIX"},
|
||||
{"$ref": "#/definitions/VDE"},
|
||||
{"$ref": "#/definitions/NULL"},
|
||||
]
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port", "nio"]
|
||||
}
|
||||
|
||||
ETHHUB_DELETE_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete a NIO for an Ethernet hub instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port"]
|
||||
}
|
||||
|
||||
ETHHUB_START_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to start a packet capture on an Ethernet hub instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet hub instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"capture_file_name": {
|
||||
"description": "Capture file name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"data_link_type": {
|
||||
"description": "PCAP data link type",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port", "capture_file_name"]
|
||||
}
|
||||
|
||||
ETHHUB_STOP_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to stop a packet capture on an Ethernet hub instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet hub instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port"]
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
ETHSW_CREATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to create a new Ethernet switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Ethernet switch name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name"]
|
||||
}
|
||||
|
||||
ETHSW_DELETE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete an Ethernet switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
# TODO: ports {'1': {'vlan': 1, 'type': 'qinq'}
|
||||
ETHSW_UPDATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to update an Ethernet switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"description": "Ethernet switch name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
# "ports": {
|
||||
# "type": "object",
|
||||
# "properties": {
|
||||
# "type": {
|
||||
# "description": "Port type",
|
||||
# "enum": ["access", "dot1q", "qinq"],
|
||||
# },
|
||||
# "vlan": {
|
||||
# "description": "VLAN number",
|
||||
# "type": "integer",
|
||||
# "minimum": 1
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
},
|
||||
#"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
ETHSW_ALLOCATE_UDP_PORT_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to allocate an UDP port for an Ethernet switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id"]
|
||||
}
|
||||
|
||||
ETHSW_ADD_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to add a NIO for an Ethernet switch instance",
|
||||
"type": "object",
|
||||
|
||||
"definitions": {
|
||||
"UDP": {
|
||||
"description": "UDP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_udp"]
|
||||
},
|
||||
"lport": {
|
||||
"description": "Local port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"rhost": {
|
||||
"description": "Remote host",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"rport": {
|
||||
"description": "Remote port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
}
|
||||
},
|
||||
"required": ["type", "lport", "rhost", "rport"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"Ethernet": {
|
||||
"description": "Generic Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_generic_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"LinuxEthernet": {
|
||||
"description": "Linux Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_linux_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"TAP": {
|
||||
"description": "TAP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_tap"]
|
||||
},
|
||||
"tap_device": {
|
||||
"description": "TAP device name e.g. tap0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "tap_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"UNIX": {
|
||||
"description": "UNIX Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_unix"]
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the UNIX socket file (local)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"remote_file": {
|
||||
"description": "path to the UNIX socket file (remote)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "local_file", "remote_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"VDE": {
|
||||
"description": "VDE Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_vde"]
|
||||
},
|
||||
"control_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "control_file", "local_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"NULL": {
|
||||
"description": "NULL Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_null"]
|
||||
},
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
},
|
||||
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"port_type": {
|
||||
"description": "Port type",
|
||||
"enum": ["access", "dot1q", "qinq"],
|
||||
},
|
||||
"vlan": {
|
||||
"description": "VLAN number",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"nio": {
|
||||
"type": "object",
|
||||
"description": "Network Input/Output",
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/UDP"},
|
||||
{"$ref": "#/definitions/Ethernet"},
|
||||
{"$ref": "#/definitions/LinuxEthernet"},
|
||||
{"$ref": "#/definitions/TAP"},
|
||||
{"$ref": "#/definitions/UNIX"},
|
||||
{"$ref": "#/definitions/VDE"},
|
||||
{"$ref": "#/definitions/NULL"},
|
||||
]
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port", "port_type", "vlan", "nio"],
|
||||
|
||||
"dependencies": {
|
||||
"port_type": ["vlan"],
|
||||
"vlan": ["port_type"]
|
||||
}
|
||||
}
|
||||
|
||||
ETHSW_DELETE_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete a NIO for an Ethernet switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port"]
|
||||
}
|
||||
|
||||
ETHSW_START_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to start a packet capture on an Ethernet switch instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"capture_file_name": {
|
||||
"description": "Capture file name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"data_link_type": {
|
||||
"description": "PCAP data link type",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port", "capture_file_name"]
|
||||
}
|
||||
|
||||
ETHSW_STOP_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to stop a packet capture on an Ethernet switch instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port"]
|
||||
}
|
@ -1,322 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
FRSW_CREATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to create a new Frame relay switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Frame relay switch name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name"]
|
||||
}
|
||||
|
||||
FRSW_DELETE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete a Frame relay switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Frame relay switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
FRSW_UPDATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to update a Frame relay switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Frame relay switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"description": "Frame relay switch name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
FRSW_ALLOCATE_UDP_PORT_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to allocate an UDP port for a Frame relay switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Frame relay switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Frame relay switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id"]
|
||||
}
|
||||
|
||||
FRSW_ADD_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to add a NIO for a Frame relay switch instance",
|
||||
"type": "object",
|
||||
|
||||
"definitions": {
|
||||
"UDP": {
|
||||
"description": "UDP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_udp"]
|
||||
},
|
||||
"lport": {
|
||||
"description": "Local port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"rhost": {
|
||||
"description": "Remote host",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"rport": {
|
||||
"description": "Remote port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
}
|
||||
},
|
||||
"required": ["type", "lport", "rhost", "rport"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"Ethernet": {
|
||||
"description": "Generic Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_generic_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"LinuxEthernet": {
|
||||
"description": "Linux Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_linux_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"TAP": {
|
||||
"description": "TAP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_tap"]
|
||||
},
|
||||
"tap_device": {
|
||||
"description": "TAP device name e.g. tap0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "tap_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"UNIX": {
|
||||
"description": "UNIX Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_unix"]
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the UNIX socket file (local)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"remote_file": {
|
||||
"description": "path to the UNIX socket file (remote)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "local_file", "remote_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"VDE": {
|
||||
"description": "VDE Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_vde"]
|
||||
},
|
||||
"control_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "control_file", "local_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"NULL": {
|
||||
"description": "NULL Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_null"]
|
||||
},
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
},
|
||||
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Frame relay switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Frame relay switch instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"mappings": {
|
||||
"type": "object",
|
||||
},
|
||||
"nio": {
|
||||
"type": "object",
|
||||
"description": "Network Input/Output",
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/UDP"},
|
||||
{"$ref": "#/definitions/Ethernet"},
|
||||
{"$ref": "#/definitions/LinuxEthernet"},
|
||||
{"$ref": "#/definitions/TAP"},
|
||||
{"$ref": "#/definitions/UNIX"},
|
||||
{"$ref": "#/definitions/VDE"},
|
||||
{"$ref": "#/definitions/NULL"},
|
||||
]
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port", "port_id", "mappings", "nio"],
|
||||
}
|
||||
|
||||
FRSW_DELETE_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete a NIO for a Frame relay switch instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Frame relay switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port"]
|
||||
}
|
||||
|
||||
FRSW_START_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to start a packet capture on a Frame relay switch instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Frame relay switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Frame relay instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"capture_file_name": {
|
||||
"description": "Capture file name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"data_link_type": {
|
||||
"description": "PCAP data link type",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port", "capture_file_name"]
|
||||
}
|
||||
|
||||
FRSW_STOP_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to stop a packet capture on a Frame relay switch instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Frame relay switch instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Frame relay instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port"]
|
||||
}
|
@ -1,719 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
VM_CREATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to create a new VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Router name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"router_id": {
|
||||
"description": "VM/router instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"platform": {
|
||||
"description": "router platform",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^c[0-9]{4}$"
|
||||
},
|
||||
"chassis": {
|
||||
"description": "router chassis model",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^[0-9]{4}(XM)?$"
|
||||
},
|
||||
"image": {
|
||||
"description": "path to the IOS image file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"ram": {
|
||||
"description": "amount of RAM in MB",
|
||||
"type": "integer"
|
||||
},
|
||||
"console": {
|
||||
"description": "console TCP port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"aux": {
|
||||
"description": "auxiliary console TCP port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"mac_addr": {
|
||||
"description": "base MAC address",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$"
|
||||
},
|
||||
"cloud_path": {
|
||||
"description": "Path to the image in the cloud object store",
|
||||
"type": "string",
|
||||
}
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name", "platform", "image", "ram"]
|
||||
}
|
||||
|
||||
VM_DELETE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete a VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
VM_START_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to start a VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
VM_STOP_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to stop a VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
VM_SUSPEND_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to suspend a VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
VM_RELOAD_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to reload a VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
# TODO: improve platform specific properties (dependencies?)
|
||||
VM_UPDATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to update a VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"description": "Router name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"platform": {
|
||||
"description": "platform",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^c[0-9]{4}$"
|
||||
},
|
||||
"image": {
|
||||
"description": "path to the IOS image",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"startup_config": {
|
||||
"description": "path to the IOS startup configuration file",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"private_config": {
|
||||
"description": "path to the IOS private configuration file",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"ram": {
|
||||
"description": "amount of RAM in MB",
|
||||
"type": "integer"
|
||||
},
|
||||
"nvram": {
|
||||
"description": "amount of NVRAM in KB",
|
||||
"type": "integer"
|
||||
},
|
||||
"mmap": {
|
||||
"description": "MMAP feature",
|
||||
"type": "boolean"
|
||||
},
|
||||
"sparsemem": {
|
||||
"description": "sparse memory feature",
|
||||
"type": "boolean"
|
||||
},
|
||||
"clock_divisor": {
|
||||
"description": "clock divisor",
|
||||
"type": "integer"
|
||||
},
|
||||
"idlepc": {
|
||||
"description": "Idle-PC value",
|
||||
"type": "string",
|
||||
"pattern": "^(0x[0-9a-fA-F]+)?$"
|
||||
},
|
||||
"idlemax": {
|
||||
"description": "idlemax value",
|
||||
"type": "integer",
|
||||
},
|
||||
"idlesleep": {
|
||||
"description": "idlesleep value",
|
||||
"type": "integer",
|
||||
},
|
||||
"exec_area": {
|
||||
"description": "exec area value",
|
||||
"type": "integer",
|
||||
},
|
||||
"jit_sharing_group": {
|
||||
"description": "JIT sharing group",
|
||||
"type": "integer",
|
||||
},
|
||||
"disk0": {
|
||||
"description": "disk0 size in MB",
|
||||
"type": "integer"
|
||||
},
|
||||
"disk1": {
|
||||
"description": "disk1 size in MB",
|
||||
"type": "integer"
|
||||
},
|
||||
"confreg": {
|
||||
"description": "configuration register",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^0x[0-9a-fA-F]{4}$"
|
||||
},
|
||||
"console": {
|
||||
"description": "console TCP port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"aux": {
|
||||
"description": "auxiliary console TCP port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"mac_addr": {
|
||||
"description": "base MAC address",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$"
|
||||
},
|
||||
"system_id": {
|
||||
"description": "system ID",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"slot0": {
|
||||
"description": "Network module slot 0",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"slot1": {
|
||||
"description": "Network module slot 1",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"slot2": {
|
||||
"description": "Network module slot 2",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"slot3": {
|
||||
"description": "Network module slot 3",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"slot4": {
|
||||
"description": "Network module slot 4",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"slot5": {
|
||||
"description": "Network module slot 5",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"slot6": {
|
||||
"description": "Network module slot 6",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"wic0": {
|
||||
"description": "Network module WIC slot 0",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"wic1": {
|
||||
"description": "Network module WIC slot 0",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"wic2": {
|
||||
"description": "Network module WIC slot 0",
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"startup_config_base64": {
|
||||
"description": "startup configuration base64 encoded",
|
||||
"type": "string"
|
||||
},
|
||||
"private_config_base64": {
|
||||
"description": "private configuration base64 encoded",
|
||||
"type": "string"
|
||||
},
|
||||
# C7200 properties
|
||||
"npe": {
|
||||
"description": "NPE model",
|
||||
"enum": ["npe-100",
|
||||
"npe-150",
|
||||
"npe-175",
|
||||
"npe-200",
|
||||
"npe-225",
|
||||
"npe-300",
|
||||
"npe-400",
|
||||
"npe-g2"]
|
||||
},
|
||||
"midplane": {
|
||||
"description": "Midplane model",
|
||||
"enum": ["std", "vxr"]
|
||||
},
|
||||
"sensors": {
|
||||
"description": "Temperature sensors",
|
||||
"type": "array"
|
||||
},
|
||||
"power_supplies": {
|
||||
"description": "Power supplies status",
|
||||
"type": "array"
|
||||
},
|
||||
# I/O memory property for all platforms but C7200
|
||||
"iomem": {
|
||||
"description": "I/O memory percentage",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
VM_START_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to start a packet capture on a VM instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the VM instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"slot": {
|
||||
"description": "Slot number",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 6
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 49 # maximum is 16 for regular port numbers, WICs port numbers start at 16, 32 or 48
|
||||
},
|
||||
"capture_file_name": {
|
||||
"description": "Capture file name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"data_link_type": {
|
||||
"description": "PCAP data link type",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "slot", "port", "capture_file_name"]
|
||||
}
|
||||
|
||||
VM_STOP_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to stop a packet capture on a VM instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the VM instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"slot": {
|
||||
"description": "Slot number",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 6
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 49 # maximum is 16 for regular port numbers, WICs port numbers start at 16, 32 or 48
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "slot", "port"]
|
||||
}
|
||||
|
||||
VM_SAVE_CONFIG_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to save the configs for VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
VM_EXPORT_CONFIG_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to export the configs for VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
VM_IDLEPCS_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to calculate or show Idle-PCs for VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"compute": {
|
||||
"description": "indicates to compute new Idle-PC values",
|
||||
"type": "boolean"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
VM_AUTO_IDLEPC_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request an auto Idle-PC calculation for this VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
VM_ALLOCATE_UDP_PORT_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to allocate an UDP port for a VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the VM instance",
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id"]
|
||||
}
|
||||
|
||||
VM_ADD_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to add a NIO for a VM instance",
|
||||
"type": "object",
|
||||
|
||||
"definitions": {
|
||||
"UDP": {
|
||||
"description": "UDP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_udp"]
|
||||
},
|
||||
"lport": {
|
||||
"description": "Local port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"rhost": {
|
||||
"description": "Remote host",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"rport": {
|
||||
"description": "Remote port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
}
|
||||
},
|
||||
"required": ["type", "lport", "rhost", "rport"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"Ethernet": {
|
||||
"description": "Generic Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_generic_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"LinuxEthernet": {
|
||||
"description": "Linux Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_linux_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"TAP": {
|
||||
"description": "TAP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_tap"]
|
||||
},
|
||||
"tap_device": {
|
||||
"description": "TAP device name e.g. tap0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "tap_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"UNIX": {
|
||||
"description": "UNIX Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_unix"]
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the UNIX socket file (local)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"remote_file": {
|
||||
"description": "path to the UNIX socket file (remote)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "local_file", "remote_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"VDE": {
|
||||
"description": "VDE Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_vde"]
|
||||
},
|
||||
"control_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "control_file", "local_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"NULL": {
|
||||
"description": "NULL Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_null"]
|
||||
},
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
},
|
||||
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the VM instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"slot": {
|
||||
"description": "Slot number",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 6
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 49 # maximum is 16 for regular port numbers, WICs port numbers start at 16, 32 or 48
|
||||
},
|
||||
"nio": {
|
||||
"type": "object",
|
||||
"description": "Network Input/Output",
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/UDP"},
|
||||
{"$ref": "#/definitions/Ethernet"},
|
||||
{"$ref": "#/definitions/LinuxEthernet"},
|
||||
{"$ref": "#/definitions/TAP"},
|
||||
{"$ref": "#/definitions/UNIX"},
|
||||
{"$ref": "#/definitions/VDE"},
|
||||
{"$ref": "#/definitions/NULL"},
|
||||
]
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "slot", "port", "nio"]
|
||||
}
|
||||
|
||||
VM_DELETE_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete a NIO for a VM instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "VM instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"slot": {
|
||||
"description": "Slot number",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 6
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 49 # maximum is 16 for regular port numbers, WICs port numbers start at 16, 32 or 48
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "slot", "port"]
|
||||
}
|
108
gns3server/schemas/dynamips.py
Normal file
108
gns3server/schemas/dynamips.py
Normal file
@ -0,0 +1,108 @@
|
||||
# -*- 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/>.
|
||||
|
||||
|
||||
ROUTER_CREATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to create a new Dynamips router instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Router name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"router_id": {
|
||||
"description": "VM/router instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"platform": {
|
||||
"description": "router platform",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^c[0-9]{4}$"
|
||||
},
|
||||
"chassis": {
|
||||
"description": "router chassis model",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^[0-9]{4}(XM)?$"
|
||||
},
|
||||
"image": {
|
||||
"description": "path to the IOS image file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"ram": {
|
||||
"description": "amount of RAM in MB",
|
||||
"type": "integer"
|
||||
},
|
||||
"console": {
|
||||
"description": "console TCP port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"aux": {
|
||||
"description": "auxiliary console TCP port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"mac_addr": {
|
||||
"description": "base MAC address",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$"
|
||||
},
|
||||
"cloud_path": {
|
||||
"description": "Path to the image in the cloud object store",
|
||||
"type": "string",
|
||||
}
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name", "platform", "image", "ram"]
|
||||
}
|
||||
|
||||
ROUTER_OBJECT_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Dynamips router instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Dynamips router instance name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"vm_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}$"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name", "vm_id", "project_id"]
|
||||
}
|
Loading…
Reference in New Issue
Block a user