diff --git a/gns3server/handlers/__init__.py b/gns3server/handlers/__init__.py index de1a5c0b..727b4053 100644 --- a/gns3server/handlers/__init__.py +++ b/gns3server/handlers/__init__.py @@ -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"] diff --git a/gns3server/handlers/dynamips_handler.py b/gns3server/handlers/dynamips_handler.py new file mode 100644 index 00000000..f7929708 --- /dev/null +++ b/gns3server/handlers/dynamips_handler.py @@ -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 . + +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) diff --git a/gns3server/modules/__init__.py b/gns3server/modules/__init__.py index 5127dd83..4e2f51bb 100644 --- a/gns3server/modules/__init__.py +++ b/gns3server/modules/__init__.py @@ -15,8 +15,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys from .vpcs import VPCS from .virtualbox import VirtualBox +from .dynamips import Dynamips -MODULES = [VPCS, VirtualBox] +MODULES = [VPCS, VirtualBox, Dynamips] diff --git a/gns3server/modules/dynamips/__init__.py b/gns3server/modules/dynamips/__init__.py new file mode 100644 index 00000000..9e9246bd --- /dev/null +++ b/gns3server/modules/dynamips/__init__.py @@ -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 . + +""" +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) diff --git a/gns3server/old_modules/dynamips/adapters/__init__.py b/gns3server/modules/dynamips/adapters/__init__.py similarity index 100% rename from gns3server/old_modules/dynamips/adapters/__init__.py rename to gns3server/modules/dynamips/adapters/__init__.py diff --git a/gns3server/old_modules/dynamips/adapters/adapter.py b/gns3server/modules/dynamips/adapters/adapter.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/adapter.py rename to gns3server/modules/dynamips/adapters/adapter.py index 40d82c7e..d963933e 100644 --- a/gns3server/old_modules/dynamips/adapters/adapter.py +++ b/gns3server/modules/dynamips/adapters/adapter.py @@ -17,7 +17,6 @@ class Adapter(object): - """ Base class for adapters. diff --git a/gns3server/old_modules/dynamips/adapters/c1700_mb_1fe.py b/gns3server/modules/dynamips/adapters/c1700_mb_1fe.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/c1700_mb_1fe.py rename to gns3server/modules/dynamips/adapters/c1700_mb_1fe.py index c94f551d..3c67f3df 100644 --- a/gns3server/old_modules/dynamips/adapters/c1700_mb_1fe.py +++ b/gns3server/modules/dynamips/adapters/c1700_mb_1fe.py @@ -19,7 +19,6 @@ from .adapter import Adapter class C1700_MB_1FE(Adapter): - """ Integrated 1 port FastEthernet adapter for c1700 platform. """ diff --git a/gns3server/old_modules/dynamips/adapters/c1700_mb_wic1.py b/gns3server/modules/dynamips/adapters/c1700_mb_wic1.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/c1700_mb_wic1.py rename to gns3server/modules/dynamips/adapters/c1700_mb_wic1.py index 9c6d2190..eca72358 100644 --- a/gns3server/old_modules/dynamips/adapters/c1700_mb_wic1.py +++ b/gns3server/modules/dynamips/adapters/c1700_mb_wic1.py @@ -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. diff --git a/gns3server/old_modules/dynamips/adapters/c2600_mb_1e.py b/gns3server/modules/dynamips/adapters/c2600_mb_1e.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/c2600_mb_1e.py rename to gns3server/modules/dynamips/adapters/c2600_mb_1e.py index bebe7fa9..26fe5497 100644 --- a/gns3server/old_modules/dynamips/adapters/c2600_mb_1e.py +++ b/gns3server/modules/dynamips/adapters/c2600_mb_1e.py @@ -19,7 +19,6 @@ from .adapter import Adapter class C2600_MB_1E(Adapter): - """ Integrated 1 port Ethernet adapter for the c2600 platform. """ diff --git a/gns3server/old_modules/dynamips/adapters/c2600_mb_1fe.py b/gns3server/modules/dynamips/adapters/c2600_mb_1fe.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/c2600_mb_1fe.py rename to gns3server/modules/dynamips/adapters/c2600_mb_1fe.py index 1ad294f2..768d9c95 100644 --- a/gns3server/old_modules/dynamips/adapters/c2600_mb_1fe.py +++ b/gns3server/modules/dynamips/adapters/c2600_mb_1fe.py @@ -19,7 +19,6 @@ from .adapter import Adapter class C2600_MB_1FE(Adapter): - """ Integrated 1 port FastEthernet adapter for the c2600 platform. """ diff --git a/gns3server/old_modules/dynamips/adapters/c2600_mb_2e.py b/gns3server/modules/dynamips/adapters/c2600_mb_2e.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/c2600_mb_2e.py rename to gns3server/modules/dynamips/adapters/c2600_mb_2e.py index 1e42d5dd..c2ca7442 100644 --- a/gns3server/old_modules/dynamips/adapters/c2600_mb_2e.py +++ b/gns3server/modules/dynamips/adapters/c2600_mb_2e.py @@ -19,7 +19,6 @@ from .adapter import Adapter class C2600_MB_2E(Adapter): - """ Integrated 2 port Ethernet adapter for the c2600 platform. """ diff --git a/gns3server/old_modules/dynamips/adapters/c2600_mb_2fe.py b/gns3server/modules/dynamips/adapters/c2600_mb_2fe.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/c2600_mb_2fe.py rename to gns3server/modules/dynamips/adapters/c2600_mb_2fe.py index dcd96581..a7e6df14 100644 --- a/gns3server/old_modules/dynamips/adapters/c2600_mb_2fe.py +++ b/gns3server/modules/dynamips/adapters/c2600_mb_2fe.py @@ -19,7 +19,6 @@ from .adapter import Adapter class C2600_MB_2FE(Adapter): - """ Integrated 2 port FastEthernet adapter for the c2600 platform. """ diff --git a/gns3server/old_modules/dynamips/adapters/c7200_io_2fe.py b/gns3server/modules/dynamips/adapters/c7200_io_2fe.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/c7200_io_2fe.py rename to gns3server/modules/dynamips/adapters/c7200_io_2fe.py index 8b545e99..0b8ae8a4 100644 --- a/gns3server/old_modules/dynamips/adapters/c7200_io_2fe.py +++ b/gns3server/modules/dynamips/adapters/c7200_io_2fe.py @@ -19,7 +19,6 @@ from .adapter import Adapter class C7200_IO_2FE(Adapter): - """ C7200-IO-2FE FastEthernet Input/Ouput controller. """ diff --git a/gns3server/old_modules/dynamips/adapters/c7200_io_fe.py b/gns3server/modules/dynamips/adapters/c7200_io_fe.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/c7200_io_fe.py rename to gns3server/modules/dynamips/adapters/c7200_io_fe.py index 784b154d..56e86cf1 100644 --- a/gns3server/old_modules/dynamips/adapters/c7200_io_fe.py +++ b/gns3server/modules/dynamips/adapters/c7200_io_fe.py @@ -19,7 +19,6 @@ from .adapter import Adapter class C7200_IO_FE(Adapter): - """ C7200-IO-FE FastEthernet Input/Ouput controller. """ diff --git a/gns3server/old_modules/dynamips/adapters/c7200_io_ge_e.py b/gns3server/modules/dynamips/adapters/c7200_io_ge_e.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/c7200_io_ge_e.py rename to gns3server/modules/dynamips/adapters/c7200_io_ge_e.py index f233dffd..12ebaed6 100644 --- a/gns3server/old_modules/dynamips/adapters/c7200_io_ge_e.py +++ b/gns3server/modules/dynamips/adapters/c7200_io_ge_e.py @@ -19,7 +19,6 @@ from .adapter import Adapter class C7200_IO_GE_E(Adapter): - """ C7200-IO-GE-E GigabitEthernet Input/Ouput controller. """ diff --git a/gns3server/old_modules/dynamips/adapters/gt96100_fe.py b/gns3server/modules/dynamips/adapters/gt96100_fe.py similarity index 100% rename from gns3server/old_modules/dynamips/adapters/gt96100_fe.py rename to gns3server/modules/dynamips/adapters/gt96100_fe.py diff --git a/gns3server/old_modules/dynamips/adapters/leopard_2fe.py b/gns3server/modules/dynamips/adapters/leopard_2fe.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/leopard_2fe.py rename to gns3server/modules/dynamips/adapters/leopard_2fe.py index db6ad9c2..0afa95c0 100644 --- a/gns3server/old_modules/dynamips/adapters/leopard_2fe.py +++ b/gns3server/modules/dynamips/adapters/leopard_2fe.py @@ -19,7 +19,6 @@ from .adapter import Adapter class Leopard_2FE(Adapter): - """ Integrated 2 port FastEthernet adapter for c3660 router. """ diff --git a/gns3server/old_modules/dynamips/adapters/nm_16esw.py b/gns3server/modules/dynamips/adapters/nm_16esw.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/nm_16esw.py rename to gns3server/modules/dynamips/adapters/nm_16esw.py index 31e74565..fc3755cd 100644 --- a/gns3server/old_modules/dynamips/adapters/nm_16esw.py +++ b/gns3server/modules/dynamips/adapters/nm_16esw.py @@ -19,7 +19,6 @@ from .adapter import Adapter class NM_16ESW(Adapter): - """ NM-16ESW FastEthernet network module. """ diff --git a/gns3server/old_modules/dynamips/adapters/nm_1e.py b/gns3server/modules/dynamips/adapters/nm_1e.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/nm_1e.py rename to gns3server/modules/dynamips/adapters/nm_1e.py index 59ac5569..ac200247 100644 --- a/gns3server/old_modules/dynamips/adapters/nm_1e.py +++ b/gns3server/modules/dynamips/adapters/nm_1e.py @@ -19,7 +19,6 @@ from .adapter import Adapter class NM_1E(Adapter): - """ NM-1E Ethernet network module. """ diff --git a/gns3server/old_modules/dynamips/adapters/nm_1fe_tx.py b/gns3server/modules/dynamips/adapters/nm_1fe_tx.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/nm_1fe_tx.py rename to gns3server/modules/dynamips/adapters/nm_1fe_tx.py index 26568306..9723f703 100644 --- a/gns3server/old_modules/dynamips/adapters/nm_1fe_tx.py +++ b/gns3server/modules/dynamips/adapters/nm_1fe_tx.py @@ -19,7 +19,6 @@ from .adapter import Adapter class NM_1FE_TX(Adapter): - """ NM-1FE-TX FastEthernet network module. """ diff --git a/gns3server/old_modules/dynamips/adapters/nm_4e.py b/gns3server/modules/dynamips/adapters/nm_4e.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/nm_4e.py rename to gns3server/modules/dynamips/adapters/nm_4e.py index 086b04ee..ae6a51ed 100644 --- a/gns3server/old_modules/dynamips/adapters/nm_4e.py +++ b/gns3server/modules/dynamips/adapters/nm_4e.py @@ -19,7 +19,6 @@ from .adapter import Adapter class NM_4E(Adapter): - """ NM-4E Ethernet network module. """ diff --git a/gns3server/old_modules/dynamips/adapters/nm_4t.py b/gns3server/modules/dynamips/adapters/nm_4t.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/nm_4t.py rename to gns3server/modules/dynamips/adapters/nm_4t.py index 77c3ecc8..df6db299 100644 --- a/gns3server/old_modules/dynamips/adapters/nm_4t.py +++ b/gns3server/modules/dynamips/adapters/nm_4t.py @@ -19,7 +19,6 @@ from .adapter import Adapter class NM_4T(Adapter): - """ NM-4T Serial network module. """ diff --git a/gns3server/old_modules/dynamips/adapters/pa_2fe_tx.py b/gns3server/modules/dynamips/adapters/pa_2fe_tx.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/pa_2fe_tx.py rename to gns3server/modules/dynamips/adapters/pa_2fe_tx.py index 09b677f3..8589ff2e 100644 --- a/gns3server/old_modules/dynamips/adapters/pa_2fe_tx.py +++ b/gns3server/modules/dynamips/adapters/pa_2fe_tx.py @@ -19,7 +19,6 @@ from .adapter import Adapter class PA_2FE_TX(Adapter): - """ PA-2FE-TX FastEthernet port adapter. """ diff --git a/gns3server/old_modules/dynamips/adapters/pa_4e.py b/gns3server/modules/dynamips/adapters/pa_4e.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/pa_4e.py rename to gns3server/modules/dynamips/adapters/pa_4e.py index d5981860..32564992 100644 --- a/gns3server/old_modules/dynamips/adapters/pa_4e.py +++ b/gns3server/modules/dynamips/adapters/pa_4e.py @@ -19,7 +19,6 @@ from .adapter import Adapter class PA_4E(Adapter): - """ PA-4E Ethernet port adapter. """ diff --git a/gns3server/old_modules/dynamips/adapters/pa_4t.py b/gns3server/modules/dynamips/adapters/pa_4t.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/pa_4t.py rename to gns3server/modules/dynamips/adapters/pa_4t.py index 5a1393bc..6a098a24 100644 --- a/gns3server/old_modules/dynamips/adapters/pa_4t.py +++ b/gns3server/modules/dynamips/adapters/pa_4t.py @@ -19,7 +19,6 @@ from .adapter import Adapter class PA_4T(Adapter): - """ PA-4T+ Serial port adapter. """ diff --git a/gns3server/old_modules/dynamips/adapters/pa_8e.py b/gns3server/modules/dynamips/adapters/pa_8e.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/pa_8e.py rename to gns3server/modules/dynamips/adapters/pa_8e.py index 96684055..a6b5075f 100644 --- a/gns3server/old_modules/dynamips/adapters/pa_8e.py +++ b/gns3server/modules/dynamips/adapters/pa_8e.py @@ -19,7 +19,6 @@ from .adapter import Adapter class PA_8E(Adapter): - """ PA-8E Ethernet port adapter. """ diff --git a/gns3server/old_modules/dynamips/adapters/pa_8t.py b/gns3server/modules/dynamips/adapters/pa_8t.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/pa_8t.py rename to gns3server/modules/dynamips/adapters/pa_8t.py index 723e026f..600a5c29 100644 --- a/gns3server/old_modules/dynamips/adapters/pa_8t.py +++ b/gns3server/modules/dynamips/adapters/pa_8t.py @@ -19,7 +19,6 @@ from .adapter import Adapter class PA_8T(Adapter): - """ PA-8T Serial port adapter. """ diff --git a/gns3server/old_modules/dynamips/adapters/pa_a1.py b/gns3server/modules/dynamips/adapters/pa_a1.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/pa_a1.py rename to gns3server/modules/dynamips/adapters/pa_a1.py index 469d9ce4..21d51f15 100644 --- a/gns3server/old_modules/dynamips/adapters/pa_a1.py +++ b/gns3server/modules/dynamips/adapters/pa_a1.py @@ -19,7 +19,6 @@ from .adapter import Adapter class PA_A1(Adapter): - """ PA-A1 ATM port adapter. """ diff --git a/gns3server/old_modules/dynamips/adapters/pa_fe_tx.py b/gns3server/modules/dynamips/adapters/pa_fe_tx.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/pa_fe_tx.py rename to gns3server/modules/dynamips/adapters/pa_fe_tx.py index 6434d2b4..70ce8489 100644 --- a/gns3server/old_modules/dynamips/adapters/pa_fe_tx.py +++ b/gns3server/modules/dynamips/adapters/pa_fe_tx.py @@ -19,7 +19,6 @@ from .adapter import Adapter class PA_FE_TX(Adapter): - """ PA-FE-TX FastEthernet port adapter. """ diff --git a/gns3server/old_modules/dynamips/adapters/pa_ge.py b/gns3server/modules/dynamips/adapters/pa_ge.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/pa_ge.py rename to gns3server/modules/dynamips/adapters/pa_ge.py index e466d905..f0287408 100644 --- a/gns3server/old_modules/dynamips/adapters/pa_ge.py +++ b/gns3server/modules/dynamips/adapters/pa_ge.py @@ -19,7 +19,6 @@ from .adapter import Adapter class PA_GE(Adapter): - """ PA-GE GigabitEthernet port adapter. """ diff --git a/gns3server/old_modules/dynamips/adapters/pa_pos_oc3.py b/gns3server/modules/dynamips/adapters/pa_pos_oc3.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/pa_pos_oc3.py rename to gns3server/modules/dynamips/adapters/pa_pos_oc3.py index de0bc5d1..b120de97 100644 --- a/gns3server/old_modules/dynamips/adapters/pa_pos_oc3.py +++ b/gns3server/modules/dynamips/adapters/pa_pos_oc3.py @@ -19,7 +19,6 @@ from .adapter import Adapter class PA_POS_OC3(Adapter): - """ PA-POS-OC3 port adapter. """ diff --git a/gns3server/old_modules/dynamips/adapters/wic_1enet.py b/gns3server/modules/dynamips/adapters/wic_1enet.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/wic_1enet.py rename to gns3server/modules/dynamips/adapters/wic_1enet.py index 2d5e62b7..dac79b6b 100644 --- a/gns3server/old_modules/dynamips/adapters/wic_1enet.py +++ b/gns3server/modules/dynamips/adapters/wic_1enet.py @@ -17,7 +17,6 @@ class WIC_1ENET(object): - """ WIC-1ENET Ethernet """ diff --git a/gns3server/old_modules/dynamips/adapters/wic_1t.py b/gns3server/modules/dynamips/adapters/wic_1t.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/wic_1t.py rename to gns3server/modules/dynamips/adapters/wic_1t.py index 2067246d..0f7cb3ad 100644 --- a/gns3server/old_modules/dynamips/adapters/wic_1t.py +++ b/gns3server/modules/dynamips/adapters/wic_1t.py @@ -17,7 +17,6 @@ class WIC_1T(object): - """ WIC-1T Serial """ diff --git a/gns3server/old_modules/dynamips/adapters/wic_2t.py b/gns3server/modules/dynamips/adapters/wic_2t.py similarity index 99% rename from gns3server/old_modules/dynamips/adapters/wic_2t.py rename to gns3server/modules/dynamips/adapters/wic_2t.py index b5af954e..2bf2d565 100644 --- a/gns3server/old_modules/dynamips/adapters/wic_2t.py +++ b/gns3server/modules/dynamips/adapters/wic_2t.py @@ -17,7 +17,6 @@ class WIC_2T(object): - """ WIC-2T Serial """ diff --git a/gns3server/old_modules/dynamips/dynamips_error.py b/gns3server/modules/dynamips/dynamips_error.py similarity index 96% rename from gns3server/old_modules/dynamips/dynamips_error.py rename to gns3server/modules/dynamips/dynamips_error.py index 332c6bbb..58c306ee 100644 --- a/gns3server/old_modules/dynamips/dynamips_error.py +++ b/gns3server/modules/dynamips/dynamips_error.py @@ -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 diff --git a/gns3server/old_modules/dynamips/dynamips_hypervisor.py b/gns3server/modules/dynamips/dynamips_hypervisor.py similarity index 58% rename from gns3server/old_modules/dynamips/dynamips_hypervisor.py rename to gns3server/modules/dynamips/dynamips_hypervisor.py index 1ac01ee1..954d6d4b 100644 --- a/gns3server/old_modules/dynamips/dynamips_hypervisor.py +++ b/gns3server/modules/dynamips/dynamips_hypervisor.py @@ -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())) diff --git a/gns3server/old_modules/dynamips/hypervisor.py b/gns3server/modules/dynamips/hypervisor.py similarity index 57% rename from gns3server/old_modules/dynamips/hypervisor.py rename to gns3server/modules/dynamips/hypervisor.py index ffce2935..87e05f75 100644 --- a/gns3server/old_modules/dynamips/hypervisor.py +++ b/gns3server/modules/dynamips/hypervisor.py @@ -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 diff --git a/gns3server/old_modules/dynamips/backends/__init__.py b/gns3server/modules/dynamips/nios/__init__.py similarity index 100% rename from gns3server/old_modules/dynamips/backends/__init__.py rename to gns3server/modules/dynamips/nios/__init__.py diff --git a/gns3server/old_modules/dynamips/nios/nio.py b/gns3server/modules/dynamips/nios/nio.py similarity index 79% rename from gns3server/old_modules/dynamips/nios/nio.py rename to gns3server/modules/dynamips/nios/nio.py index 3b66d54f..256ddc1b 100644 --- a/gns3server/old_modules/dynamips/nios/nio.py +++ b/gns3server/modules/dynamips/nios/nio.py @@ -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. diff --git a/gns3server/old_modules/dynamips/nios/nio_fifo.py b/gns3server/modules/dynamips/nios/nio_fifo.py similarity index 85% rename from gns3server/old_modules/dynamips/nios/nio_fifo.py rename to gns3server/modules/dynamips/nios/nio_fifo.py index c85b679d..768d87af 100644 --- a/gns3server/old_modules/dynamips/nios/nio_fifo.py +++ b/gns3server/modules/dynamips/nios/nio_fifo.py @@ -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)) diff --git a/gns3server/old_modules/dynamips/nios/nio_generic_ethernet.py b/gns3server/modules/dynamips/nios/nio_generic_ethernet.py similarity index 87% rename from gns3server/old_modules/dynamips/nios/nio_generic_ethernet.py rename to gns3server/modules/dynamips/nios/nio_generic_ethernet.py index 2a8b1443..4428e2bf 100644 --- a/gns3server/old_modules/dynamips/nios/nio_generic_ethernet.py +++ b/gns3server/modules/dynamips/nios/nio_generic_ethernet.py @@ -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): """ diff --git a/gns3server/old_modules/dynamips/nios/nio_linux_ethernet.py b/gns3server/modules/dynamips/nios/nio_linux_ethernet.py similarity index 87% rename from gns3server/old_modules/dynamips/nios/nio_linux_ethernet.py rename to gns3server/modules/dynamips/nios/nio_linux_ethernet.py index 25988aa8..28bfbe89 100644 --- a/gns3server/old_modules/dynamips/nios/nio_linux_ethernet.py +++ b/gns3server/modules/dynamips/nios/nio_linux_ethernet.py @@ -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): """ diff --git a/gns3server/old_modules/dynamips/nios/nio_mcast.py b/gns3server/modules/dynamips/nios/nio_mcast.py similarity index 83% rename from gns3server/old_modules/dynamips/nios/nio_mcast.py rename to gns3server/modules/dynamips/nios/nio_mcast.py index bcd42670..fe32135b 100644 --- a/gns3server/old_modules/dynamips/nios/nio_mcast.py +++ b/gns3server/modules/dynamips/nios/nio_mcast.py @@ -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 diff --git a/gns3server/old_modules/dynamips/nios/nio_null.py b/gns3server/modules/dynamips/nios/nio_null.py similarity index 90% rename from gns3server/old_modules/dynamips/nios/nio_null.py rename to gns3server/modules/dynamips/nios/nio_null.py index 1cde2a52..b8113e59 100644 --- a/gns3server/old_modules/dynamips/nios/nio_null.py +++ b/gns3server/modules/dynamips/nios/nio_null.py @@ -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)) diff --git a/gns3server/old_modules/dynamips/nios/nio_tap.py b/gns3server/modules/dynamips/nios/nio_tap.py similarity index 85% rename from gns3server/old_modules/dynamips/nios/nio_tap.py rename to gns3server/modules/dynamips/nios/nio_tap.py index d24e9109..efe47a9e 100644 --- a/gns3server/old_modules/dynamips/nios/nio_tap.py +++ b/gns3server/modules/dynamips/nios/nio_tap.py @@ -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): """ diff --git a/gns3server/old_modules/dynamips/nios/nio_udp.py b/gns3server/modules/dynamips/nios/nio_udp.py similarity index 83% rename from gns3server/old_modules/dynamips/nios/nio_udp.py rename to gns3server/modules/dynamips/nios/nio_udp.py index d9e2d294..0bae8bbf 100644 --- a/gns3server/old_modules/dynamips/nios/nio_udp.py +++ b/gns3server/modules/dynamips/nios/nio_udp.py @@ -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): """ diff --git a/gns3server/old_modules/dynamips/nios/nio_udp_auto.py b/gns3server/modules/dynamips/nios/nio_udp_auto.py similarity index 83% rename from gns3server/old_modules/dynamips/nios/nio_udp_auto.py rename to gns3server/modules/dynamips/nios/nio_udp_auto.py index 03d290d6..eb42e580 100644 --- a/gns3server/old_modules/dynamips/nios/nio_udp_auto.py +++ b/gns3server/modules/dynamips/nios/nio_udp_auto.py @@ -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 diff --git a/gns3server/old_modules/dynamips/nios/nio_unix.py b/gns3server/modules/dynamips/nios/nio_unix.py similarity index 85% rename from gns3server/old_modules/dynamips/nios/nio_unix.py rename to gns3server/modules/dynamips/nios/nio_unix.py index af100d2e..af913f88 100644 --- a/gns3server/old_modules/dynamips/nios/nio_unix.py +++ b/gns3server/modules/dynamips/nios/nio_unix.py @@ -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): """ diff --git a/gns3server/old_modules/dynamips/nios/nio_vde.py b/gns3server/modules/dynamips/nios/nio_vde.py similarity index 99% rename from gns3server/old_modules/dynamips/nios/nio_vde.py rename to gns3server/modules/dynamips/nios/nio_vde.py index 7157834f..79af96d7 100644 --- a/gns3server/old_modules/dynamips/nios/nio_vde.py +++ b/gns3server/modules/dynamips/nios/nio_vde.py @@ -26,7 +26,6 @@ log = logging.getLogger(__name__) class NIO_VDE(NIO): - """ Dynamips VDE NIO. diff --git a/gns3server/old_modules/dynamips/nios/__init__.py b/gns3server/modules/dynamips/nodes/__init__.py similarity index 100% rename from gns3server/old_modules/dynamips/nios/__init__.py rename to gns3server/modules/dynamips/nodes/__init__.py diff --git a/gns3server/old_modules/dynamips/nodes/c1700.py b/gns3server/modules/dynamips/nodes/c1700.py similarity index 99% rename from gns3server/old_modules/dynamips/nodes/c1700.py rename to gns3server/modules/dynamips/nodes/c1700.py index 249ab508..906abe3e 100644 --- a/gns3server/old_modules/dynamips/nodes/c1700.py +++ b/gns3server/modules/dynamips/nodes/c1700.py @@ -29,7 +29,6 @@ log = logging.getLogger(__name__) class C1700(Router): - """ Dynamips c1700 router. diff --git a/gns3server/old_modules/dynamips/nodes/c2600.py b/gns3server/modules/dynamips/nodes/c2600.py similarity index 99% rename from gns3server/old_modules/dynamips/nodes/c2600.py rename to gns3server/modules/dynamips/nodes/c2600.py index 083bbce6..b5e46e89 100644 --- a/gns3server/old_modules/dynamips/nodes/c2600.py +++ b/gns3server/modules/dynamips/nodes/c2600.py @@ -31,7 +31,6 @@ log = logging.getLogger(__name__) class C2600(Router): - """ Dynamips c2600 router. diff --git a/gns3server/old_modules/dynamips/nodes/c2691.py b/gns3server/modules/dynamips/nodes/c2691.py similarity index 99% rename from gns3server/old_modules/dynamips/nodes/c2691.py rename to gns3server/modules/dynamips/nodes/c2691.py index fca62624..0dc0ef28 100644 --- a/gns3server/old_modules/dynamips/nodes/c2691.py +++ b/gns3server/modules/dynamips/nodes/c2691.py @@ -28,7 +28,6 @@ log = logging.getLogger(__name__) class C2691(Router): - """ Dynamips c2691 router. diff --git a/gns3server/old_modules/dynamips/nodes/c3600.py b/gns3server/modules/dynamips/nodes/c3600.py similarity index 99% rename from gns3server/old_modules/dynamips/nodes/c3600.py rename to gns3server/modules/dynamips/nodes/c3600.py index 8b9e8966..32e2bbe7 100644 --- a/gns3server/old_modules/dynamips/nodes/c3600.py +++ b/gns3server/modules/dynamips/nodes/c3600.py @@ -28,7 +28,6 @@ log = logging.getLogger(__name__) class C3600(Router): - """ Dynamips c3600 router. diff --git a/gns3server/old_modules/dynamips/nodes/c3725.py b/gns3server/modules/dynamips/nodes/c3725.py similarity index 99% rename from gns3server/old_modules/dynamips/nodes/c3725.py rename to gns3server/modules/dynamips/nodes/c3725.py index 76ba4d9f..9317a393 100644 --- a/gns3server/old_modules/dynamips/nodes/c3725.py +++ b/gns3server/modules/dynamips/nodes/c3725.py @@ -28,7 +28,6 @@ log = logging.getLogger(__name__) class C3725(Router): - """ Dynamips c3725 router. diff --git a/gns3server/old_modules/dynamips/nodes/c3745.py b/gns3server/modules/dynamips/nodes/c3745.py similarity index 99% rename from gns3server/old_modules/dynamips/nodes/c3745.py rename to gns3server/modules/dynamips/nodes/c3745.py index 0903b789..8002909a 100644 --- a/gns3server/old_modules/dynamips/nodes/c3745.py +++ b/gns3server/modules/dynamips/nodes/c3745.py @@ -28,7 +28,6 @@ log = logging.getLogger(__name__) class C3745(Router): - """ Dynamips c3745 router. diff --git a/gns3server/old_modules/dynamips/nodes/c7200.py b/gns3server/modules/dynamips/nodes/c7200.py similarity index 97% rename from gns3server/old_modules/dynamips/nodes/c7200.py rename to gns3server/modules/dynamips/nodes/c7200.py index 8ba10f8e..21ab4aa6 100644 --- a/gns3server/old_modules/dynamips/nodes/c7200.py +++ b/gns3server/modules/dynamips/nodes/c7200.py @@ -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 diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py new file mode 100644 index 00000000..722100f4 --- /dev/null +++ b/gns3server/modules/dynamips/nodes/router.py @@ -0,0 +1,1514 @@ +# -*- 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 . + +""" +Interface for Dynamips virtual Machine module ("vm") +http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L77 +""" + +from ...base_vm import BaseVM +from ..dynamips_error import DynamipsError + +import asyncio +import time +import sys +import os +import base64 + +import logging +log = logging.getLogger(__name__) + + +class Router(BaseVM): + + """ + Dynamips router implementation. + """ + + _status = {0: "inactive", + 1: "shutting down", + 2: "running", + 3: "suspended"} + + def __init__(self, name, vm_id, project, manager, platform="c7200", ghost_flag=False): + + super().__init__(name, vm_id, project, manager) + + self._hypervisor = None + self._closed = False + self._name = name + self._platform = platform + self._image = "" + self._startup_config = "" + self._private_config = "" + self._ram = 128 # Megabytes + self._nvram = 128 # Kilobytes + self._mmap = True + self._sparsemem = True + self._clock_divisor = 8 + self._idlepc = "" + self._idlemax = 500 + self._idlesleep = 30 + self._ghost_file = "" + self._ghost_status = 0 + if sys.platform.startswith("win"): + self._exec_area = 16 # 16 MB by default on Windows (Cygwin) + else: + self._exec_area = 64 # 64 MB on other systems + self._disk0 = 0 # Megabytes + self._disk1 = 0 # Megabytes + self._confreg = "0x2102" + self._console = None + self._aux = None + self._mac_addr = None + self._system_id = "FTX0945W0MY" # processor board ID in IOS + self._slots = [] + self._ghost_flag = ghost_flag + + if not ghost_flag: + + if self._console is not None: + self._console = self._manager.port_manager.reserve_console_port(self._console) + else: + self._console = self._manager.port_manager.get_free_console_port() + + if self._aux is not None: + self._aux = self._manager.port_manager.reserve_console_port(self._aux) + else: + self._aux = self._manager.port_manager.get_free_console_port() + + def __json__(self): + + router_info = {"name": self.name, + "vm_id": self.id, + "project_id": self.project.id, + "platform": self._platform, + "image": self._image, + "startup_config": self._startup_config, + "private_config": self._private_config, + "ram": self._ram, + "nvram": self._nvram, + "mmap": self._mmap, + "sparsemem": self._sparsemem, + "clock_divisor": self._clock_divisor, + "idlepc": self._idlepc, + "idlemax": self._idlemax, + "idlesleep": self._idlesleep, + "exec_area": self._exec_area, + "disk0": self._disk0, + "disk1": self._disk1, + "confreg": self._confreg, + "console": self._console, + "aux": self._aux, + "mac_addr": self._mac_addr, + "system_id": self._system_id} + + # FIXME: add default slots/wics + #slot_id = 0 + #for slot in self._slots: + # if slot: + # slot = str(slot) + # router_defaults["slot" + str(slot_id)] = slot + # slot_id += 1 + + #if self._slots[0] and self._slots[0].wics: + # for wic_slot_id in range(0, len(self._slots[0].wics)): + # router_defaults["wic" + str(wic_slot_id)] = None + + return router_info + + @asyncio.coroutine + def create(self): + + self._hypervisor = yield from self.manager.start_new_hypervisor() + + yield from self._hypervisor.send("vm create '{name}' {id} {platform}".format(name=self._name, + id=self._id, + platform=self._platform)) + + if not self._ghost_flag: + + log.info("Router {platform} '{name}' [{id}] has been created".format(name=self._name, + platform=self._platform, + id=self._id)) + + yield from self._hypervisor.send("vm set_con_tcp_port '{name}' {console}".format(name=self._name, console=self._console)) + yield from self._hypervisor.send("vm set_aux_tcp_port '{name}' {aux}".format(name=self._name, aux=self._aux)) + + # get the default base MAC address + mac_addr = yield from self._hypervisor.send("{platform} get_mac_addr '{name}'".format(platform=self._platform, + name=self._name)) + self._mac_addr = mac_addr[0] + + self._hypervisor.devices.append(self) + + @asyncio.coroutine + def get_status(self): + """ + Returns the status of this router + + :returns: inactive, shutting down, running or suspended. + """ + + status = yield from self._hypervisor.send("vm get_status '{name}'".format(name=self._name)) + return self._status[int(status[0])] + + @asyncio.coroutine + def start(self): + """ + Starts this router. + At least the IOS image must be set before it can start. + """ + + status = yield from self.get_status() + if status == "suspended": + yield from self.resume() + elif status == "inactive": + + if not os.path.isfile(self._image) or not os.path.exists(self._image): + if os.path.islink(self._image): + raise DynamipsError("IOS image '{}' linked to '{}' is not accessible".format(self._image, os.path.realpath(self._image))) + else: + raise DynamipsError("IOS image '{}' is not accessible".format(self._image)) + + try: + with open(self._image, "rb") as f: + # read the first 7 bytes of the file. + elf_header_start = f.read(7) + except OSError as e: + raise DynamipsError("Cannot read ELF header for IOS image {}: {}".format(self._image, e)) + + # IOS images must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1 + if elf_header_start != b'\x7fELF\x01\x02\x01': + raise DynamipsError("'{}' is not a valid IOS image".format(self._image)) + + yield from self._hypervisor.send("vm start '{}'".format(self._name)) + log.info("router '{name}' [{id}] has been started".format(name=self._name, id=self._id)) + + @asyncio.coroutine + def stop(self): + """ + Stops this router. + """ + + status = yield from self.get_status() + if status != "inactive": + yield from self._hypervisor.send("vm stop '{name}'".format(self._name)) + log.info("Router '{name}' [{id}] has been stopped".format(name=self._name, id=self._id)) + + @asyncio.coroutine + def suspend(self): + """ + Suspends this router. + """ + + status = yield from self.get_status() + if status == "running": + yield from self._hypervisor.send("vm suspend '{}'".format(self._name)) + log.info("Router '{name}' [{id}] has been suspended".format(name=self._name, id=self._id)) + + @asyncio.coroutine + def resume(self): + """ + Resumes this suspended router + """ + + yield from self._hypervisor.send("vm resume '{}'".format(self._name)) + log.info("Router '{name}' [{id}] has been resumed".format(name=self._name, id=self._id)) + + @asyncio.coroutine + def is_running(self): + """ + Checks if this router is running. + + :returns: True if running, False otherwise + """ + + status = yield from self.get_status() + if status == "running": + return True + return False + + @asyncio.coroutine + def close(self): + + if self._closed: + # router is already closed + return + + if self._hypervisor: + yield from self.stop() + yield from self.hypervisor.stop() + + if self._console: + self._manager.port_manager.release_console_port(self._console) + self._console = None + + if self._aux: + self._manager.port_manager.release_console_port(self._aux) + self._aux = None + + self._closed = True + + @asyncio.coroutine + def delete(self): + """ + Deletes this router. + """ + + yield from self.close() + yield from self._hypervisor.send("vm delete '{}'".format(self._name)) + self._hypervisor.devices.remove(self) + log.info("router '{name}' [{id}] has been deleted".format(name=self._name, id=self._id)) + + @property + def platform(self): + """ + Returns the platform of this router. + + :returns: platform name (string): + c7200, c3745, c3725, c3600, c2691, c2600 or c1700 + """ + + return self._platform + + @property + def hypervisor(self): + """ + Returns the current hypervisor. + + :returns: hypervisor instance + """ + + return self._hypervisor + + @asyncio.coroutine + def list(self): + """ + Returns all VM instances + + :returns: list of all VM instances + """ + + vm_list = yield from self._hypervisor.send("vm list") + return vm_list + + @asyncio.coroutine + def list_con_ports(self): + """ + Returns all VM console TCP ports + + :returns: list of port numbers + """ + + port_list = yield from self._hypervisor.send("vm list_con_ports") + return port_list + + @asyncio.coroutine + def set_debug_level(self, level): + """ + Sets the debug level for this router (default is 0). + + :param level: level number + """ + + yield from self._hypervisor.send("vm set_debug_level '{name}' {level}".format(name=self._name, level=level)) + + @property + def image(self): + """ + Returns this IOS image for this router. + + :returns: path to IOS image file + """ + + return self._image + + @asyncio.coroutine + def set_image(self, image): + """ + Sets the IOS image for this router. + There is no default. + + :param image: path to IOS image file + """ + + # encase image in quotes to protect spaces in the path + yield from self._hypervisor.send("vm set_ios {name} {image}".format(name=self._name, image='"' + image + '"')) + + log.info("Router '{name}' [{id}]: has a new IOS image set: {image}".format(name=self._name, + id=self._id, + image='"' + image + '"')) + + self._image = image + + @property + def ram(self): + """ + Returns the amount of RAM allocated to this router. + + :returns: amount of RAM in Mbytes (integer) + """ + + return self._ram + + @asyncio.coroutine + def set_ram(self, ram): + """ + Sets amount of RAM allocated to this router + + :param ram: amount of RAM in Mbytes (integer) + """ + + if self._ram == ram: + return + + yield from self._hypervisor.send("vm set_ram '{name}' {ram}".format(name=self._name, ram=ram)) + log.info("Router '{name}' [{id}]: RAM updated from {old_ram}MB to {new_ram}MB".format(name=self._name, + id=self._id, + old_ram=self._ram, + new_ram=ram)) + self._ram = ram + + @property + def nvram(self): + """ + Returns the mount of NVRAM allocated to this router. + + :returns: amount of NVRAM in Kbytes (integer) + """ + + return self._nvram + + @asyncio.coroutine + def set_nvram(self, nvram): + """ + Sets amount of NVRAM allocated to this router + + :param nvram: amount of NVRAM in Kbytes (integer) + """ + + if self._nvram == nvram: + return + + yield from self._hypervisor.send("vm set_nvram '{name}' {nvram}".format(name=self._name, nvram=nvram)) + log.info("Router '{name}' [{id}]: NVRAM updated from {old_nvram}KB to {new_nvram}KB".format(name=self._name, + id=self._id, + old_nvram=self._nvram, + new_nvram=nvram)) + self._nvram = nvram + + @property + def mmap(self): + """ + Returns True if a mapped file is used to simulate this router memory. + + :returns: boolean either mmap is activated or not + """ + + return self._mmap + + @asyncio.coroutine + def set_mmap(self, mmap): + """ + Enable/Disable use of a mapped file to simulate router memory. + By default, a mapped file is used. This is a bit slower, but requires less memory. + + :param mmap: activate/deactivate mmap (boolean) + """ + + if mmap: + flag = 1 + else: + flag = 0 + + yield from self._hypervisor.send("vm set_ram_mmap '{name}' {mmap}".format(name=self._name, mmap=flag)) + + if mmap: + log.info("Router '{name}' [{id}]: mmap enabled".format(name=self._name, id=self._id)) + else: + log.info("Router '{name}' [{id}]: mmap disabled".format(name=self._name, id=self._id)) + self._mmap = mmap + + @property + def sparsemem(self): + """ + Returns True if sparse memory is used on this router. + + :returns: boolean either mmap is activated or not + """ + + return self._sparsemem + + @asyncio.coroutine + def set_sparsemem(self, sparsemem): + """ + Enable/disable use of sparse memory + + :param sparsemem: activate/deactivate sparsemem (boolean) + """ + + if sparsemem: + flag = 1 + else: + flag = 0 + yield from self._hypervisor.send("vm set_sparse_mem '{name}' {sparsemem}".format(name=self._name, sparsemem=flag)) + + if sparsemem: + log.info("Router '{name}' [{id}]: sparse memory enabled".format(name=self._name, id=self._id)) + else: + log.info("Router '{name}' [{id}]: sparse memory disabled".format(name=self._name, id=self._id)) + self._sparsemem = sparsemem + + @property + def clock_divisor(self): + """ + Returns the clock divisor value for this router. + + :returns: clock divisor value (integer) + """ + + return self._clock_divisor + + @asyncio.coroutine + def set_clock_divisor(self, clock_divisor): + """ + Sets the clock divisor value. The higher is the value, the faster is the clock in the + virtual machine. The default is 4, but it is often required to adjust it. + + :param clock_divisor: clock divisor value (integer) + """ + + yield from self._hypervisor.send("vm set_clock_divisor '{name}' {clock}".format(name=self._name, clock=clock_divisor)) + log.info("Router '{name}' [{id}]: clock divisor updated from {old_clock} to {new_clock}".format(name=self._name, + id=self._id, + old_clock=self._clock_divisor, + new_clock=clock_divisor)) + self._clock_divisor = clock_divisor + + @property + def idlepc(self): + """ + Returns the idle Pointer Counter (PC). + + :returns: idlepc value (string) + """ + + return self._idlepc + + @asyncio.coroutine + def set_idlepc(self, idlepc): + """ + Sets the idle Pointer Counter (PC) + + :param idlepc: idlepc value (string) + """ + + if not idlepc: + idlepc = "0x0" + + is_running = yield from self.is_running() + if not is_running: + # router is not running + yield from self._hypervisor.send("vm set_idle_pc '{name}' {idlepc}".format(name=self._name, idlepc=idlepc)) + else: + yield from self._hypervisor.send("vm set_idle_pc_online '{name}' 0 {idlepc}".format(name=self._name, idlepc=idlepc)) + + log.info("Router '{name}' [{id}]: idle-PC set to {idlepc}".format(name=self._name, id=self._id, idlepc=idlepc)) + self._idlepc = idlepc + + @asyncio.coroutine + def get_idle_pc_prop(self): + """ + Gets the idle PC proposals. + Takes 1000 measurements and records up to 10 idle PC proposals. + There is a 10ms wait between each measurement. + + :returns: list of idle PC proposal + """ + + is_running = yield from self.is_running() + if not is_running: + # router is not running + raise DynamipsError("Router '{name}' is not running".format(name=self._name)) + + log.info("Router '{name}' [{id}] has started calculating Idle-PC values".format(name=self._name, id=self._id)) + begin = time.time() + idlepcs = yield from self._hypervisor.send("vm get_idle_pc_prop '{}' 0".format(self._name)) + log.info("Router '{name}' [{id}] has finished calculating Idle-PC values after {time:.4f} seconds".format(name=self._name, + id=self._id, + time=time.time() - begin)) + return idlepcs + + @asyncio.coroutine + def show_idle_pc_prop(self): + """ + Dumps the idle PC proposals (previously generated). + + :returns: list of idle PC proposal + """ + + is_running = yield from self.is_running() + if not is_running: + # router is not running + raise DynamipsError("Router '{name}' is not running".format(name=self._name)) + + proposals = yield from self._hypervisor.send("vm show_idle_pc_prop '{}' 0".format(self._name)) + return proposals + + @property + def idlemax(self): + """ + Returns CPU idle max value. + + :returns: idle max (integer) + """ + + return self._idlemax + + @asyncio.coroutine + def set_idlemax(self, idlemax): + """ + Sets CPU idle max value + + :param idlemax: idle max value (integer) + """ + + is_running = yield from self.is_running() + if is_running: # router is running + yield from self._hypervisor.send("vm set_idle_max '{name}' 0 {idlemax}".format(name=self._name, idlemax=idlemax)) + + log.info("Router '{name}' [{id}]: idlemax updated from {old_idlemax} to {new_idlemax}".format(name=self._name, + id=self._id, + old_idlemax=self._idlemax, + new_idlemax=idlemax)) + + self._idlemax = idlemax + + @property + def idlesleep(self): + """ + Returns CPU idle sleep time value. + + :returns: idle sleep (integer) + """ + + return self._idlesleep + + @asyncio.coroutine + def set_idlesleep(self, idlesleep): + """ + Sets CPU idle sleep time value. + + :param idlesleep: idle sleep value (integer) + """ + + is_running = yield from self.is_running() + if is_running: # router is running + yield from self._hypervisor.send("vm set_idle_sleep_time '{name}' 0 {idlesleep}".format(name=self._name, + idlesleep=idlesleep)) + + log.info("Router '{name}' [{id}]: idlesleep updated from {old_idlesleep} to {new_idlesleep}".format(name=self._name, + id=self._id, + old_idlesleep=self._idlesleep, + new_idlesleep=idlesleep)) + + self._idlesleep = idlesleep + + @property + def ghost_file(self): + """ + Returns ghost RAM file. + + :returns: path to ghost file + """ + + return self._ghost_file + + @asyncio.coroutine + def set_ghost_file(self, ghost_file): + """ + Sets ghost RAM file + + :ghost_file: path to ghost file + """ + + yield from self._hypervisor.send("vm set_ghost_file '{name}' {ghost_file}".format(name=self._name, + ghost_file=ghost_file)) + + log.info("Router '{name}' [{id}]: ghost file set to {ghost_file}".format(name=self._name, + id=self._id, + ghost_file=ghost_file)) + + self._ghost_file = ghost_file + + # this is a ghost instance, track this as a hosted ghost instance by this hypervisor + if self.ghost_status == 1: + self._hypervisor.add_ghost(ghost_file, self) + + def formatted_ghost_file(self): + """ + Returns a properly formatted ghost file name. + + :returns: formatted ghost_file name (string) + """ + + # replace specials characters in 'drive:\filename' in Linux and Dynamips in MS Windows or viceversa. + ghost_file = "{}-{}.ghost".format(os.path.basename(self._image), self._ram) + ghost_file = ghost_file.replace('\\', '-').replace('/', '-').replace(':', '-') + return ghost_file + + @property + def ghost_status(self): + """Returns ghost RAM status + + :returns: ghost status (integer) + """ + + return self._ghost_status + + @asyncio.coroutine + def set_ghost_status(self, ghost_status): + """ + Sets ghost RAM status + + :param ghost_status: state flag indicating status + 0 => Do not use IOS ghosting + 1 => This is a ghost instance + 2 => Use an existing ghost instance + """ + + yield from self._hypervisor.send("vm set_ghost_status '{name}' {ghost_status}".format(name=self._name, + ghost_status=ghost_status)) + + log.info("Router '{name}' [{id}]: ghost status set to {ghost_status}".format(name=self._name, + id=self._id, + ghost_status=ghost_status)) + self._ghost_status = ghost_status + + @property + def exec_area(self): + """ + Returns the exec area value. + + :returns: exec area value (integer) + """ + + return self._exec_area + + @asyncio.coroutine + def set_exec_area(self, exec_area): + """ + Sets the exec area value. + The exec area is a pool of host memory used to store pages + translated by the JIT (they contain the native code + corresponding to MIPS code pages). + + :param exec_area: exec area value (integer) + """ + + yield from self._hypervisor.send("vm set_exec_area '{name}' {exec_area}".format(name=self._name, + exec_area=exec_area)) + + log.info("Router '{name}' [{id}]: exec area updated from {old_exec}MB to {new_exec}MB".format(name=self._name, + id=self._id, + old_exec=self._exec_area, + new_exec=exec_area)) + self._exec_area = exec_area + + @property + def disk0(self): + """ + Returns the size (MB) for PCMCIA disk0. + + :returns: disk0 size (integer) + """ + + return self._disk0 + + @asyncio.coroutine + def set_disk0(self, disk0): + """ + Sets the size (MB) for PCMCIA disk0. + + :param disk0: disk0 size (integer) + """ + + yield from self._hypervisor.send("vm set_disk0 '{name}' {disk0}".format(name=self._name, disk0=disk0)) + + log.info("Router {name} [{id}]: disk0 updated from {old_disk0}MB to {new_disk0}MB".format(name=self._name, + id=self._id, + old_disk0=self._disk0, + new_disk0=disk0)) + self._disk0 = disk0 + + @property + def disk1(self): + """ + Returns the size (MB) for PCMCIA disk1. + + :returns: disk1 size (integer) + """ + + return self._disk1 + + @asyncio.coroutine + def disk1(self, disk1): + """ + Sets the size (MB) for PCMCIA disk1. + + :param disk1: disk1 size (integer) + """ + + yield from self._hypervisor.send("vm set_disk1 '{name}' {disk1}".format(name=self._name, disk1=disk1)) + + log.info("Router '{name}' [{id}]: disk1 updated from {old_disk1}MB to {new_disk1}MB".format(name=self._name, + id=self._id, + old_disk1=self._disk1, + new_disk1=disk1)) + self._disk1 = disk1 + + @property + def confreg(self): + """ + Returns the configuration register. + The default is 0x2102. + + :returns: configuration register value (string) + """ + + return self._confreg + + @asyncio.coroutine + def set_confreg(self, confreg): + """ + Sets the configuration register. + + :param confreg: configuration register value (string) + """ + + yield from self._hypervisor.send("vm set_conf_reg '{name}' {confreg}".format(name=self._name, confreg=confreg)) + + log.info("Router '{name}' [{id}]: confreg updated from {old_confreg} to {new_confreg}".format(name=self._name, + id=self._id, + old_confreg=self._confreg, + new_confreg=confreg)) + self._confreg = confreg + + @property + def console(self): + """ + Returns the TCP console port. + + :returns: console port (integer) + """ + + return self._console + + @asyncio.coroutine + def set_console(self, console): + """ + Sets the TCP console port. + + :param console: console port (integer) + """ + + yield from self._hypervisor.send("vm set_con_tcp_port '{name}' {console}".format(name=self._name, console=console)) + + log.info("Router '{name}' [{id}]: console port updated from {old_console} to {new_console}".format(name=self._name, + id=self._id, + old_console=self._console, + new_console=console)) + + self._manager.port_manager.release_console_port(self._console) + self._console = self._manager.port_manager.reserve_console_port(console) + + @property + def aux(self): + """ + Returns the TCP auxiliary port. + + :returns: console auxiliary port (integer) + """ + + return self._aux + + @asyncio.coroutine + def set_aux(self, aux): + """ + Sets the TCP auxiliary port. + + :param aux: console auxiliary port (integer) + """ + + yield from self._hypervisor.send("vm set_aux_tcp_port '{name}' {aux}".format(name=self._name, aux=aux)) + + log.info("Router '{name}' [{id}]: aux port updated from {old_aux} to {new_aux}".format(name=self._name, + id=self._id, + old_aux=self._aux, + new_aux=aux)) + + self._manager.port_manager.release_console_port(self._aux) + self._aux = self._manager.port_manager.reserve_console_port(aux) + + @asyncio.coroutine + def get_cpu_usage(self, cpu_id=0): + """ + Shows cpu usage in seconds, "cpu_id" is ignored. + + :returns: cpu usage in seconds + """ + + cpu_usage = yield from self._hypervisor.send("vm cpu_usage '{name}' {cpu_id}".format(name=self._name, cpu_id=cpu_id)) + return int(cpu_usage[0]) + + @property + def mac_addr(self): + """ + Returns the MAC address. + + :returns: the MAC address (hexadecimal format: hh:hh:hh:hh:hh:hh) + """ + + return self._mac_addr + + @asyncio.coroutine + def set_mac_addr(self, mac_addr): + """ + Sets the MAC address. + + :param mac_addr: a MAC address (hexadecimal format: hh:hh:hh:hh:hh:hh) + """ + + yield from self._hypervisor.send("{platform} set_mac_addr '{name}' {mac_addr}".format(platform=self._platform, + name=self._name, + mac_addr=mac_addr)) + + log.info("Router '{name}' [{id}]: MAC address updated from {old_mac} to {new_mac}".format(name=self._name, + id=self._id, + old_mac=self._mac_addr, + new_mac=mac_addr)) + self._mac_addr = mac_addr + + @property + def system_id(self): + """ + Returns the system ID. + + :returns: the system ID (also called board processor ID) + """ + + return self._system_id + + @asyncio.coroutine + def set_system_id(self, system_id): + """ + Sets the system ID. + + :param system_id: a system ID (also called board processor ID) + """ + + yield from self._hypervisor.send("{platform} set_system_id '{name}' {system_id}".format(platform=self._platform, + name=self._name, + system_id=system_id)) + + log.info("Router '{name'} [{id}]: system ID updated from {old_id} to {new_id}".format(name=self._name, + id=self._id, + old_id=self._system_id, + new_id=system_id)) + self._system_id = system_id + + @asyncio.coroutine + def get_slot_bindings(self): + """ + Returns slot bindings. + + :returns: slot bindings (adapter names) list + """ + + slot_bindings = yield from self._hypervisor.send("vm slot_bindings '{}'".format(self._name)) + return slot_bindings + + @asyncio.coroutine + def slot_add_binding(self, slot_id, adapter): + """ + Adds a slot binding (a module into a slot). + + :param slot_id: slot ID + :param adapter: device to add in the corresponding slot + """ + + try: + slot = self._slots[slot_id] + except IndexError: + raise DynamipsError("Slot {slot_id} doesn't exist on router '{name}'".format(name=self._name, slot_id=slot_id)) + + if slot is not None: + current_adapter = slot + raise DynamipsError("Slot {slot_id} is already occupied by adapter {adapter} on router '{name}'".format(name=self._name, + slot_id=slot_id, + adapter=current_adapter)) + + is_running = yield from self.is_running() + + # Only c7200, c3600 and c3745 (NM-4T only) support new adapter while running + if is_running and not ((self._platform == 'c7200' and not str(adapter).startswith('C7200')) + and not (self._platform == 'c3600' and self.chassis == '3660') + and not (self._platform == 'c3745' and adapter == 'NM-4T')): + raise DynamipsError("Adapter {adapter} cannot be added while router '{name} 'is running".format(adapter=adapter, + name=self._name)) + + yield from self._hypervisor.send("vm slot_add_binding '{name}' {slot_id} 0 {adapter}".format(name=self._name, + slot_id=slot_id, + adapter=adapter)) + + log.info("Router '{name}' [{id}]: adapter {adapter} inserted into slot {slot_id}".format(name=self._name, + id=self._id, + adapter=adapter, + slot_id=slot_id)) + + self._slots[slot_id] = adapter + + # Generate an OIR event if the router is running + if is_running: + + yield from self._hypervisor.send("vm slot_oir_start '{name}' {slot_id} 0".format(name=self._name, slot_id=slot_id)) + + log.info("Router '{name}' [{id}]: OIR start event sent to slot {slot_id}".format(name=self._name, + id=self._id, + slot_id=slot_id)) + + @asyncio.coroutine + def slot_remove_binding(self, slot_id): + """ + Removes a slot binding (a module from a slot). + + :param slot_id: slot ID + """ + + try: + adapter = self._slots[slot_id] + except IndexError: + raise DynamipsError("Slot {slot_id} doesn't exist on router '{name}'".format(name=self._name, slot_id=slot_id)) + + if adapter is None: + raise DynamipsError("No adapter in slot {slot_id} on router '{name}'".format(name=self._name, + slot_id=slot_id)) + + is_running = yield from self.is_running() + + # Only c7200, c3600 and c3745 (NM-4T only) support to remove adapter while running + if is_running and not ((self._platform == 'c7200' and not str(adapter).startswith('C7200')) + and not (self._platform == 'c3600' and self.chassis == '3660') + and not (self._platform == 'c3745' and adapter == 'NM-4T')): + raise DynamipsError("Adapter {adapter} cannot be removed while router '{name}' is running".format(adapter=adapter, + name=self._name)) + + # Generate an OIR event if the router is running + if is_running: + + yield from self._hypervisor.send("vm slot_oir_stop '{name}' {slot_id} 0".format(name=self._name, slot_id=slot_id)) + + log.info("router '{name}' [{id}]: OIR stop event sent to slot {slot_id}".format(name=self._name, + id=self._id, + slot_id=slot_id)) + + yield from self._hypervisor.send("vm slot_remove_binding '{name}' {slot_id} 0".format(name=self._name, slot_id=slot_id)) + + log.info("Router '{name}' [{id}]: adapter {adapter} removed from slot {slot_id}".format(name=self._name, + id=self._id, + adapter=adapter, + slot_id=slot_id)) + self._slots[slot_id] = None + + @asyncio.coroutine + def install_wic(self, wic_slot_id, wic): + """ + Installs a WIC adapter into this router. + + :param wic_slot_id: WIC slot ID + :param wic: WIC to be installed + """ + + # WICs are always installed on adapters in slot 0 + slot_id = 0 + + # Do not check if slot has an adapter because adapters with WICs interfaces + # must be inserted by default in the router and cannot be removed. + adapter = self._slots[slot_id] + + if wic_slot_id > len(adapter.wics) - 1: + raise DynamipsError("WIC slot {wic_slot_id} doesn't exist".format(wic_slot_id=wic_slot_id)) + + if not adapter.wic_slot_available(wic_slot_id): + raise DynamipsError("WIC slot {wic_slot_id} is already occupied by another WIC".format(wic_slot_id=wic_slot_id)) + + # Dynamips WICs slot IDs start on a multiple of 16 + # WIC1 = 16, WIC2 = 32 and WIC3 = 48 + internal_wic_slot_id = 16 * (wic_slot_id + 1) + yield from self._hypervisor.send("vm slot_add_binding '{name}' {slot_id} {wic_slot_id} {wic}".format(name=self._name, + slot_id=slot_id, + wic_slot_id=internal_wic_slot_id, + wic=wic)) + + log.info("Router '{name}' [{id}]: {wic} inserted into WIC slot {wic_slot_id}".format(name=self._name, + id=self._id, + wic=wic, + wic_slot_id=wic_slot_id)) + + adapter.install_wic(wic_slot_id, wic) + + @asyncio.coroutine + def uninstall_wic(self, wic_slot_id): + """ + Uninstalls a WIC adapter from this router. + + :param wic_slot_id: WIC slot ID + """ + + # WICs are always installed on adapters in slot 0 + slot_id = 0 + + # Do not check if slot has an adapter because adapters with WICs interfaces + # must be inserted by default in the router and cannot be removed. + adapter = self._slots[slot_id] + + if wic_slot_id > len(adapter.wics) - 1: + raise DynamipsError("WIC slot {wic_slot_id} doesn't exist".format(wic_slot_id=wic_slot_id)) + + if adapter.wic_slot_available(wic_slot_id): + raise DynamipsError("No WIC is installed in WIC slot {wic_slot_id}".format(wic_slot_id=wic_slot_id)) + + # Dynamips WICs slot IDs start on a multiple of 16 + # WIC1 = 16, WIC2 = 32 and WIC3 = 48 + internal_wic_slot_id = 16 * (wic_slot_id + 1) + yield from self._hypervisor.send("vm slot_remove_binding '{name}' {slot_id} {wic_slot_id}".format(name=self._name, + slot_id=slot_id, + wic_slot_id=internal_wic_slot_id)) + + log.info("Router '{name}' [{id}]: {wic} removed from WIC slot {wic_slot_id}".format(name=self._name, + id=self._id, + wic=adapter.wics[wic_slot_id], + wic_slot_id=wic_slot_id)) + adapter.uninstall_wic(wic_slot_id) + + @asyncio.coroutine + def get_slot_nio_bindings(self, slot_id): + """ + Returns slot NIO bindings. + + :param slot_id: slot ID + + :returns: list of NIO bindings + """ + + nio_bindings = yield from self._hypervisor.send("vm slot_nio_bindings '{name}' {slot_id}".format(name=self._name, + slot_id=slot_id)) + return nio_bindings + + @asyncio.coroutine + def slot_add_nio_binding(self, slot_id, port_id, nio): + """ + Adds a slot NIO binding. + + :param slot_id: slot ID + :param port_id: port ID + :param nio: NIO instance to add to the slot/port + """ + + try: + adapter = self._slots[slot_id] + except IndexError: + raise DynamipsError("Slot {slot_id} doesn't exist on router '{name}'".format(name=self._name, + slot_id=slot_id)) + if not adapter.port_exists(port_id): + raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter, + port_id=port_id)) + + yield from self._hypervisor.send("vm slot_add_nio_binding '{name}' {slot_id} {port_id} {nio}".format(name=self._name, + slot_id=slot_id, + port_id=port_id, + nio=nio)) + + log.info("Router '{name}' [{id}]: NIO {nio_name} bound to port {slot_id}/{port_id}".format(name=self._name, + id=self._id, + nio_name=nio.name, + slot_id=slot_id, + port_id=port_id)) + + yield from self.slot_enable_nio(slot_id, port_id) + adapter.add_nio(port_id, nio) + + @asyncio.coroutine + def slot_remove_nio_binding(self, slot_id, port_id): + """ + Removes a slot NIO binding. + + :param slot_id: slot ID + :param port_id: port ID + + :returns: removed NIO instance + """ + + try: + adapter = self._slots[slot_id] + except IndexError: + raise DynamipsError("Slot {slot_id} doesn't exist on router '{name}'".format(name=self._name, slot_id=slot_id)) + if not adapter.port_exists(port_id): + raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter, port_id=port_id)) + + yield from self.slot_disable_nio(slot_id, port_id) + yield from self._hypervisor.send("vm slot_remove_nio_binding '{name}' {slot_id} {port_id}".format(name=self._name, + slot_id=slot_id, + port_id=port_id)) + + nio = adapter.get_nio(port_id) + adapter.remove_nio(port_id) + + log.info("Router '{name}' [{id}]: NIO {nio_name} removed from port {slot_id}/{port_id}".format(name=self._name, + id=self._id, + nio_name=nio.name, + slot_id=slot_id, + port_id=port_id)) + + return nio + + @asyncio.coroutine + def slot_enable_nio(self, slot_id, port_id): + """ + Enables a slot NIO binding. + + :param slot_id: slot ID + :param port_id: port ID + """ + + is_running = yield from self.is_running() + if is_running: # running router + yield from self._hypervisor.send("vm slot_enable_nio '{name}' {slot_id} {port_id}".format(name=self._name, + slot_id=slot_id, + port_id=port_id)) + + log.info("Router '{name}' [{id}]: NIO enabled on port {slot_id}/{port_id}".format(name=self._name, + id=self._id, + slot_id=slot_id, + port_id=port_id)) + @asyncio.coroutine + def slot_disable_nio(self, slot_id, port_id): + """ + Disables a slot NIO binding. + + :param slot_id: slot ID + :param port_id: port ID + """ + + is_running = yield from self.is_running() + if is_running: # running router + yield from self._hypervisor.send("vm slot_disable_nio '{name}' {slot_id} {port_id}".format(name=self._name, + slot_id=slot_id, + port_id=port_id)) + + log.info("Router '{name}' [{id}]: NIO disabled on port {slot_id}/{port_id}".format(name=self._name, + id=self._id, + slot_id=slot_id, + port_id=port_id)) + + @asyncio.coroutine + def start_capture(self, slot_id, port_id, output_file, data_link_type="DLT_EN10MB"): + """ + Starts a packet capture. + + :param slot_id: slot ID + :param port_id: port ID + :param output_file: PCAP destination file for the capture + :param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB + """ + + try: + adapter = self._slots[slot_id] + except IndexError: + raise DynamipsError("Slot {slot_id} doesn't exist on router '{name}'".format(name=self._name, slot_id=slot_id)) + if not adapter.port_exists(port_id): + raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter, port_id=port_id)) + + data_link_type = data_link_type.lower() + if data_link_type.startswith("dlt_"): + data_link_type = data_link_type[4:] + + nio = adapter.get_nio(port_id) + + if nio.input_filter[0] is not None and nio.output_filter[0] is not None: + raise DynamipsError("Port {port_id} has already a filter applied on {adapter}".format(adapter=adapter, + port_id=port_id)) + + + # FIXME: capture + #try: + # os.makedirs(os.path.dirname(output_file), exist_ok=True) + #except OSError as e: + # raise DynamipsError("Could not create captures directory {}".format(e)) + + yield from nio.bind_filter("both", "capture") + yield from nio.setup_filter("both", '{} "{}"'.format(data_link_type, output_file)) + + log.info("Router '{name}' [{id}]: starting packet capture on port {slot_id}/{port_id}".format(name=self._name, + id=self._id, + nio_name=nio.name, + slot_id=slot_id, + port_id=port_id)) + @asyncio.coroutine + def stop_capture(self, slot_id, port_id): + """ + Stops a packet capture. + + :param slot_id: slot ID + :param port_id: port ID + """ + + try: + adapter = self._slots[slot_id] + except IndexError: + raise DynamipsError("Slot {slot_id} doesn't exist on router '{name}'".format(name=self._name, slot_id=slot_id)) + if not adapter.port_exists(port_id): + raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter, port_id=port_id)) + + nio = adapter.get_nio(port_id) + yield from nio.unbind_filter("both") + + log.info("Router '{name}' [{id}]: stopping packet capture on port {slot_id}/{port_id}".format(name=self._name, + id=self._id, + nio_name=nio.name, + slot_id=slot_id, + port_id=port_id)) + + def _create_slots(self, numslots): + """ + Creates the appropriate number of slots for this router. + + :param numslots: number of slots to create + """ + + self._slots = numslots * [None] + + @property + def slots(self): + """ + Returns the slots for this router. + + :return: slot list + """ + + return self._slots + + @property + def startup_config(self): + """ + Returns the startup-config for this router. + + :returns: path to startup-config file + """ + + return self._startup_config + + @startup_config.setter + def startup_config(self, startup_config): + """ + Sets the startup-config for this router. + + :param startup_config: path to startup-config file + """ + + self._startup_config = startup_config + + @property + def private_config(self): + """ + Returns the private-config for this router. + + :returns: path to private-config file + """ + + return self._private_config + + @private_config.setter + def private_config(self, private_config): + """ + Sets the private-config for this router. + + :param private_config: path to private-config file + """ + + self._private_config = private_config + + # def rename(self, new_name): + # """ + # Renames this router. + # + # :param new_name: new name string + # """ + # + # if self._startup_config: + # # change the hostname in the startup-config + # startup_config_path = os.path.join(self.hypervisor.working_dir, "configs", "i{}_startup-config.cfg".format(self.id)) + # if os.path.isfile(startup_config_path): + # try: + # with open(startup_config_path, "r+", errors="replace") as f: + # old_config = f.read() + # new_config = old_config.replace(self.name, new_name) + # f.seek(0) + # f.write(new_config) + # except OSError as e: + # raise DynamipsError("Could not amend the configuration {}: {}".format(startup_config_path, e)) + # + # if self._private_config: + # # change the hostname in the private-config + # private_config_path = os.path.join(self.hypervisor.working_dir, "configs", "i{}_private-config.cfg".format(self.id)) + # if os.path.isfile(private_config_path): + # try: + # with open(private_config_path, "r+", errors="replace") as f: + # old_config = f.read() + # new_config = old_config.replace(self.name, new_name) + # f.seek(0) + # f.write(new_config) + # except OSError as e: + # raise DynamipsError("Could not amend the configuration {}: {}".format(private_config_path, e)) + # + # new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces + # self._hypervisor.send("vm rename {name} {new_name}".format(name=self._name, + # new_name=new_name)) + # + # log.info("router {name} [id={id}]: renamed to {new_name}".format(name=self._name, + # id=self._id, + # new_name=new_name)) + # self._name = new_name + + # def set_config(self, startup_config, private_config=''): + # """ + # Sets the config files that are pushed to startup-config and + # private-config in NVRAM when the instance is started. + # + # :param startup_config: path to statup-config file + # :param private_config: path to private-config file + # (keep existing data when if an empty string) + # """ + # + # if self._startup_config != startup_config or self._private_config != private_config: + # + # self._hypervisor.send("vm set_config {name} {startup} {private}".format(name=self._name, + # startup='"' + startup_config + '"', + # private='"' + private_config + '"')) + # + # log.info("router {name} [id={id}]: has a startup-config set: {startup}".format(name=self._name, + # id=self._id, + # startup='"' + startup_config + '"')) + # + # self._startup_config = startup_config + # + # if private_config: + # log.info("router {name} [id={id}]: has a private-config set: {private}".format(name=self._name, + # id=self._id, + # private='"' + private_config + '"')) + # + # self._private_config = private_config + # + # def extract_config(self): + # """ + # Gets the contents of the config files + # startup-config and private-config from NVRAM. + # + # :returns: tuple (startup-config, private-config) base64 encoded + # """ + # + # try: + # reply = self._hypervisor.send("vm extract_config {}".format(self._name))[0].rsplit(' ', 2)[-2:] + # except IOError: + # #for some reason Dynamips gets frozen when it does not find the magic number in the NVRAM file. + # return None, None + # startup_config = reply[0][1:-1] # get statup-config and remove single quotes + # private_config = reply[1][1:-1] # get private-config and remove single quotes + # return startup_config, private_config + # + # def push_config(self, startup_config, private_config='(keep)'): + # """ + # Pushes configuration to the config files startup-config and private-config in NVRAM. + # The data is a Base64 encoded string, or '(keep)' to keep existing data. + # + # :param startup_config: statup-config string base64 encoded + # :param private_config: private-config string base64 encoded + # (keep existing data when if the value is ('keep')) + # """ + # + # self._hypervisor.send("vm push_config {name} {startup} {private}".format(name=self._name, + # startup=startup_config, + # private=private_config)) + # + # log.info("router {name} [id={id}]: new startup-config pushed".format(name=self._name, + # id=self._id)) + # + # if private_config != '(keep)': + # log.info("router {name} [id={id}]: new private-config pushed".format(name=self._name, + # id=self._id)) + # + # def save_configs(self): + # """ + # Saves the startup-config and private-config to files. + # """ + # + # if self.startup_config or self.private_config: + # startup_config_base64, private_config_base64 = self.extract_config() + # if startup_config_base64: + # try: + # config = base64.decodebytes(startup_config_base64.encode("utf-8")).decode("utf-8") + # config = "!\n" + config.replace("\r", "") + # config_path = os.path.join(self.hypervisor.working_dir, self.startup_config) + # with open(config_path, "w") as f: + # log.info("saving startup-config to {}".format(self.startup_config)) + # f.write(config) + # except OSError as e: + # raise DynamipsError("Could not save the startup configuration {}: {}".format(config_path, e)) + # + # if private_config_base64: + # try: + # config = base64.decodebytes(private_config_base64.encode("utf-8")).decode("utf-8") + # config = "!\n" + config.replace("\r", "") + # config_path = os.path.join(self.hypervisor.working_dir, self.private_config) + # with open(config_path, "w") as f: + # log.info("saving private-config to {}".format(self.private_config)) + # f.write(config) + # except OSError as e: + # raise DynamipsError("Could not save the private configuration {}: {}".format(config_path, e)) + + # def clean_delete(self): + # """ + # Deletes this router & associated files (nvram, disks etc.) + # """ + # + # self._hypervisor.send("vm clean_delete {}".format(self._name)) + # self._hypervisor.devices.remove(self) + # + # if self._startup_config: + # # delete the startup-config + # startup_config_path = os.path.join(self.hypervisor.working_dir, "configs", "{}.cfg".format(self.name)) + # if os.path.isfile(startup_config_path): + # os.remove(startup_config_path) + # + # if self._private_config: + # # delete the private-config + # private_config_path = os.path.join(self.hypervisor.working_dir, "configs", "{}-private.cfg".format(self.name)) + # if os.path.isfile(private_config_path): + # os.remove(private_config_path) + # + # log.info("router {name} [id={id}] has been deleted (including associated files)".format(name=self._name, id=self._id)) diff --git a/gns3server/modules/port_manager.py b/gns3server/modules/port_manager.py index 80e94087..da448cd6 100644 --- a/gns3server/modules/port_manager.py +++ b/gns3server/modules/port_manager.py @@ -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): diff --git a/gns3server/modules/vpcs/vpcs_vm.py b/gns3server/modules/vpcs/vpcs_vm.py index 036bfedc..9791fde0 100644 --- a/gns3server/modules/vpcs/vpcs_vm.py +++ b/gns3server/modules/vpcs/vpcs_vm.py @@ -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 diff --git a/gns3server/old_modules/dynamips/__init__.py b/gns3server/old_modules/dynamips/__init__.py deleted file mode 100644 index 26347094..00000000 --- a/gns3server/old_modules/dynamips/__init__.py +++ /dev/null @@ -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 . - -""" -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) diff --git a/gns3server/old_modules/dynamips/backends/atmsw.py b/gns3server/old_modules/dynamips/backends/atmsw.py deleted file mode 100644 index 2ce0410b..00000000 --- a/gns3server/old_modules/dynamips/backends/atmsw.py +++ /dev/null @@ -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 . - -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) diff --git a/gns3server/old_modules/dynamips/backends/ethhub.py b/gns3server/old_modules/dynamips/backends/ethhub.py deleted file mode 100644 index 97c9df7f..00000000 --- a/gns3server/old_modules/dynamips/backends/ethhub.py +++ /dev/null @@ -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 . - -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) diff --git a/gns3server/old_modules/dynamips/backends/ethsw.py b/gns3server/old_modules/dynamips/backends/ethsw.py deleted file mode 100644 index e251e158..00000000 --- a/gns3server/old_modules/dynamips/backends/ethsw.py +++ /dev/null @@ -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 . - -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) diff --git a/gns3server/old_modules/dynamips/backends/frsw.py b/gns3server/old_modules/dynamips/backends/frsw.py deleted file mode 100644 index ed63f501..00000000 --- a/gns3server/old_modules/dynamips/backends/frsw.py +++ /dev/null @@ -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 . - -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) diff --git a/gns3server/old_modules/dynamips/backends/vm.py b/gns3server/old_modules/dynamips/backends/vm.py deleted file mode 100644 index e40e79d6..00000000 --- a/gns3server/old_modules/dynamips/backends/vm.py +++ /dev/null @@ -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 . - -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) diff --git a/gns3server/old_modules/dynamips/hypervisor_manager.py b/gns3server/old_modules/dynamips/hypervisor_manager.py deleted file mode 100644 index a9be6ed0..00000000 --- a/gns3server/old_modules/dynamips/hypervisor_manager.py +++ /dev/null @@ -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 . - -""" -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 = [] diff --git a/gns3server/old_modules/dynamips/nodes/__init__.py b/gns3server/old_modules/dynamips/nodes/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/gns3server/old_modules/dynamips/nodes/atm_bridge.py b/gns3server/old_modules/dynamips/nodes/atm_bridge.py deleted file mode 100644 index bfed0b78..00000000 --- a/gns3server/old_modules/dynamips/nodes/atm_bridge.py +++ /dev/null @@ -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 . - -""" -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 diff --git a/gns3server/old_modules/dynamips/nodes/atm_switch.py b/gns3server/old_modules/dynamips/nodes/atm_switch.py deleted file mode 100644 index aa0dba3e..00000000 --- a/gns3server/old_modules/dynamips/nodes/atm_switch.py +++ /dev/null @@ -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 . - -""" -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)) diff --git a/gns3server/old_modules/dynamips/nodes/bridge.py b/gns3server/old_modules/dynamips/nodes/bridge.py deleted file mode 100644 index fcac17b9..00000000 --- a/gns3server/old_modules/dynamips/nodes/bridge.py +++ /dev/null @@ -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 . - -""" -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) diff --git a/gns3server/old_modules/dynamips/nodes/ethernet_switch.py b/gns3server/old_modules/dynamips/nodes/ethernet_switch.py deleted file mode 100644 index a88346dc..00000000 --- a/gns3server/old_modules/dynamips/nodes/ethernet_switch.py +++ /dev/null @@ -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 . - -""" -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)) diff --git a/gns3server/old_modules/dynamips/nodes/frame_relay_switch.py b/gns3server/old_modules/dynamips/nodes/frame_relay_switch.py deleted file mode 100644 index 8a309301..00000000 --- a/gns3server/old_modules/dynamips/nodes/frame_relay_switch.py +++ /dev/null @@ -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 . - -""" -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)) diff --git a/gns3server/old_modules/dynamips/nodes/hub.py b/gns3server/old_modules/dynamips/nodes/hub.py deleted file mode 100644 index 18cedbe1..00000000 --- a/gns3server/old_modules/dynamips/nodes/hub.py +++ /dev/null @@ -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 . - -""" -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)) diff --git a/gns3server/old_modules/dynamips/nodes/router.py b/gns3server/old_modules/dynamips/nodes/router.py deleted file mode 100644 index 18d8db8d..00000000 --- a/gns3server/old_modules/dynamips/nodes/router.py +++ /dev/null @@ -1,1676 +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 . - -""" -Interface for Dynamips virtual Machine module ("vm") -http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L77 -""" - -from ..dynamips_error import DynamipsError -from ...attic import find_unused_port - -import time -import sys -import os -import base64 - -import logging -log = logging.getLogger(__name__) - - -class Router(object): - - """ - Dynamips router implementation. - - :param hypervisor: Dynamips hypervisor instance - :param name: name for this router - :param router_id: router instance ID - :param platform: c7200, c3745, c3725, c3600, c2691, c2600 or c1700 - :param ghost_flag: used when creating a ghost IOS. - """ - - _instances = [] - _allocated_console_ports = [] - _allocated_aux_ports = [] - _status = {0: "inactive", - 1: "shutting down", - 2: "running", - 3: "suspended"} - - def __init__(self, hypervisor, name, router_id=None, platform="c7200", ghost_flag=False): - - if not ghost_flag: - - if not router_id: - # find an instance identifier if none is provided (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") - else: - if router_id in self._instances: - raise DynamipsError("Router identifier {} is already used by another router".format(router_id)) - self._id = router_id - self._instances.append(self._id) - - else: - log.info("creating a new ghost IOS file") - self._id = 0 - name = "Ghost" - - self._hypervisor = hypervisor - self._name = '"' + name + '"' # put name into quotes to protect spaces - self._platform = platform - self._image = "" - self._startup_config = "" - self._private_config = "" - self._ram = 128 # Megabytes - self._nvram = 128 # Kilobytes - self._mmap = True - self._sparsemem = True - self._clock_divisor = 8 - self._idlepc = "" - self._idlemax = 500 - self._idlesleep = 30 - self._ghost_file = "" - self._ghost_status = 0 - if sys.platform.startswith("win"): - self._exec_area = 16 # 16 MB by default on Windows (Cygwin) - else: - self._exec_area = 64 # 64 MB on other systems - self._jit_sharing_group = None - self._disk0 = 0 # Megabytes - self._disk1 = 0 # Megabytes - self._confreg = "0x2102" - self._console = None - self._aux = None - self._mac_addr = None - self._system_id = "FTX0945W0MY" # processor board ID in IOS - self._slots = [] - - self._hypervisor.send("vm create {name} {id} {platform}".format(name=self._name, - id=self._id, - platform=self._platform)) - - if not ghost_flag: - log.info("router {platform} {name} [id={id}] has been created".format(name=self._name, - platform=platform, - id=self._id)) - - try: - # allocate a console port - self._console = find_unused_port(self._hypervisor.console_start_port_range, - self._hypervisor.console_end_port_range, - self._hypervisor.host, - ignore_ports=self._allocated_console_ports) - - self._hypervisor.send("vm set_con_tcp_port {name} {console}".format(name=self._name, - console=self._console)) - self._allocated_console_ports.append(self._console) - - # allocate a auxiliary console port - self._aux = find_unused_port(self._hypervisor.aux_start_port_range, - self._hypervisor.aux_end_port_range, - self._hypervisor.host, - ignore_ports=self._allocated_aux_ports) - - self._hypervisor.send("vm set_aux_tcp_port {name} {aux}".format(name=self._name, - aux=self._aux)) - - self._allocated_aux_ports.append(self._aux) - except Exception as e: - raise DynamipsError(e) - - # get the default base MAC address - self._mac_addr = self._hypervisor.send("{platform} get_mac_addr {name}".format(platform=self._platform, - name=self._name))[0] - - self._hypervisor.devices.append(self) - - @classmethod - def reset(cls): - """ - Resets the instance count and the allocated instances list. - """ - - cls._instances.clear() - cls._allocated_console_ports.clear() - cls._allocated_aux_ports.clear() - - def defaults(self): - """ - Returns all the default base attribute values for routers. - - :returns: default values (dictionary) - """ - - router_defaults = {"platform": self._platform, - "image": self._image, - "startup_config": self._startup_config, - "private_config": self._private_config, - "ram": self._ram, - "nvram": self._nvram, - "mmap": self._mmap, - "sparsemem": self._sparsemem, - "clock_divisor": self._clock_divisor, - "idlepc": self._idlepc, - "idlemax": self._idlemax, - "idlesleep": self._idlesleep, - "exec_area": self._exec_area, - "jit_sharing_group": self._jit_sharing_group, - "disk0": self._disk0, - "disk1": self._disk1, - "confreg": self._confreg, - "console": self._console, - "aux": self._aux, - "mac_addr": self._mac_addr, - "system_id": self._system_id} - - slot_id = 0 - for slot in self._slots: - if slot: - slot = str(slot) - router_defaults["slot" + str(slot_id)] = slot - slot_id += 1 - - if self._slots[0] and self._slots[0].wics: - for wic_slot_id in range(0, len(self._slots[0].wics)): - router_defaults["wic" + str(wic_slot_id)] = None - - return router_defaults - - @property - def id(self): - """ - Returns the unique ID for this router. - - :returns: id (integer) - """ - - return self._id - - @property - def name(self): - """ - Returns the name of this router. - - :returns: name (string) - """ - - return self._name[1:-1] # remove quotes - - @name.setter - def name(self, new_name): - """ - Renames this router. - - :param new_name: new name string - """ - - if self._startup_config: - # change the hostname in the startup-config - startup_config_path = os.path.join(self.hypervisor.working_dir, "configs", "i{}_startup-config.cfg".format(self.id)) - if os.path.isfile(startup_config_path): - try: - with open(startup_config_path, "r+", errors="replace") as f: - old_config = f.read() - new_config = old_config.replace(self.name, new_name) - f.seek(0) - f.write(new_config) - except OSError as e: - raise DynamipsError("Could not amend the configuration {}: {}".format(startup_config_path, e)) - - if self._private_config: - # change the hostname in the private-config - private_config_path = os.path.join(self.hypervisor.working_dir, "configs", "i{}_private-config.cfg".format(self.id)) - if os.path.isfile(private_config_path): - try: - with open(private_config_path, "r+", errors="replace") as f: - old_config = f.read() - new_config = old_config.replace(self.name, new_name) - f.seek(0) - f.write(new_config) - except OSError as e: - raise DynamipsError("Could not amend the configuration {}: {}".format(private_config_path, e)) - - new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces - self._hypervisor.send("vm rename {name} {new_name}".format(name=self._name, - new_name=new_name)) - - log.info("router {name} [id={id}]: renamed to {new_name}".format(name=self._name, - id=self._id, - new_name=new_name)) - self._name = new_name - - @property - def platform(self): - """ - Returns the platform of this router. - - :returns: platform name (string): - c7200, c3745, c3725, c3600, c2691, c2600 or c1700 - """ - - return self._platform - - @property - def hypervisor(self): - """ - Returns the current hypervisor. - - :returns: hypervisor instance - """ - - return self._hypervisor - - def list(self): - """ - Returns all VM instances - - :returns: list of all VM instances - """ - - return self._hypervisor.send("vm list") - - def list_con_ports(self): - """ - Returns all VM console TCP ports - - :returns: list of port numbers - """ - - return self._hypervisor.send("vm list_con_ports") - - def delete(self): - """ - Deletes this router. - """ - - self._hypervisor.send("vm delete {}".format(self._name)) - self._hypervisor.devices.remove(self) - log.info("router {name} [id={id}] has been deleted".format(name=self._name, id=self._id)) - if self._id in self._instances: - self._instances.remove(self._id) - if self.console: - self._allocated_console_ports.remove(self.console) - if self.aux: - self._allocated_aux_ports.remove(self.aux) - - def clean_delete(self): - """ - Deletes this router & associated files (nvram, disks etc.) - """ - - self._hypervisor.send("vm clean_delete {}".format(self._name)) - self._hypervisor.devices.remove(self) - - if self._startup_config: - # delete the startup-config - startup_config_path = os.path.join(self.hypervisor.working_dir, "configs", "{}.cfg".format(self.name)) - if os.path.isfile(startup_config_path): - os.remove(startup_config_path) - - if self._private_config: - # delete the private-config - private_config_path = os.path.join(self.hypervisor.working_dir, "configs", "{}-private.cfg".format(self.name)) - if os.path.isfile(private_config_path): - os.remove(private_config_path) - - log.info("router {name} [id={id}] has been deleted (including associated files)".format(name=self._name, id=self._id)) - if self._id in self._instances: - self._instances.remove(self._id) - if self.console: - self._allocated_console_ports.remove(self.console) - if self.aux: - self._allocated_aux_ports.remove(self.aux) - - def start(self): - """ - Starts this router. - At least the IOS image must be set before starting it. - """ - - status = self.get_status() - if status == "suspended": - self.resume() - elif status == "inactive": - - if not os.path.isfile(self._image) or not os.path.exists(self._image): - if os.path.islink(self._image): - raise DynamipsError("IOS image '{}' linked to '{}' is not accessible".format(self._image, os.path.realpath(self._image))) - else: - raise DynamipsError("IOS image '{}' is not accessible".format(self._image)) - - try: - with open(self._image, "rb") as f: - # read the first 7 bytes of the file. - elf_header_start = f.read(7) - except OSError as e: - raise DynamipsError("Cannot read ELF header for IOS image {}: {}".format(self._image, e)) - - # IOS images must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1 - if elf_header_start != b'\x7fELF\x01\x02\x01': - raise DynamipsError("'{}' is not a valid IOS image".format(self._image)) - - self._hypervisor.send("vm start {}".format(self._name)) - log.info("router {name} [id={id}] has been started".format(name=self._name, id=self._id)) - - def stop(self): - """ - Stops this router. - The settings are kept. - """ - - if self.get_status() != "inactive": - self._hypervisor.send("vm stop {}".format(self._name)) - log.info("router {name} [id={id}] has been stopped".format(name=self._name, id=self._id)) - - def suspend(self): - """ - Suspends this router - """ - - if self.get_status() == "running": - self._hypervisor.send("vm suspend {}".format(self._name)) - log.info("router {name} [id={id}] has been suspended".format(name=self._name, id=self._id)) - - def resume(self): - """ - Resumes this suspended router - """ - - self._hypervisor.send("vm resume {}".format(self._name)) - log.info("router {name} [id={id}] has been resumed".format(name=self._name, id=self._id)) - - def get_status(self): - """ - Returns the status of this router - - :returns: inactive, shutting down, running or suspended. - """ - - status_id = int(self._hypervisor.send("vm get_status {}".format(self._name))[0]) - return self._status[status_id] - - def is_running(self): - """ - Checks if this router is running. - - :returns: True if running, False otherwise - """ - - if self.get_status() == "running": - return True - return False - - @property - def jit_sharing_group(self): - """ - Returns the JIT sharing group for this router. - - :returns: translation sharing group ID - """ - - return self._jit_sharing_group - - @jit_sharing_group.setter - def jit_sharing_group(self, group_id): - """ - Sets the translation sharing group (unstable). - - :param group_id: translation sharing group ID - """ - - if not self._image: - raise DynamipsError("Register an IOS image fist") - - try: - self._hypervisor.send("vm set_tsg {name} {group_id}".format(name=self._name, - group_id=group_id)) - except DynamipsError: - raise DynamipsError("JIT sharing is only supported in Dynamips >= 0.2.8-RC3 unstable") - - log.info("router {name} [id={id}]: set in JIT sharing group {group_id}".format(name=self._name, - id=self._id, - group_id=group_id)) - - self._jit_sharing_group = group_id - self._hypervisor.add_jitsharing_group(os.path.basename(self._image), group_id) - - def set_debug_level(self, level): - """ - Sets the debug level for this router (default is 0). - - :param level: level number - """ - - self._hypervisor.send("vm set_debug_level {name} {level}".format(name=self._name, - level=level)) - - @property - def image(self): - """ - Returns this IOS image for this router. - - :returns: path to IOS image file - """ - - return self._image - - @image.setter - def image(self, image): - """ - Sets the IOS image for this router. - There is no default. - - :param image: path to IOS image file - """ - - # encase image in quotes to protect spaces in the path - self._hypervisor.send("vm set_ios {name} {image}".format(name=self._name, - image='"' + image + '"')) - - log.info("router {name} [id={id}]: has a new IOS image set: {image}".format(name=self._name, - id=self._id, - image='"' + image + '"')) - - self._image = image - - @property - def startup_config(self): - """ - Returns the startup-config for this router. - - :returns: path to startup-config file - """ - - return self._startup_config - - @startup_config.setter - def startup_config(self, startup_config): - """ - Sets the startup-config for this router. - - :param startup_config: path to startup-config file - """ - - self._startup_config = startup_config - - @property - def private_config(self): - """ - Returns the private-config for this router. - - :returns: path to private-config file - """ - - return self._private_config - - @private_config.setter - def private_config(self, private_config): - """ - Sets the private-config for this router. - - :param private_config: path to private-config file - """ - - self._private_config = private_config - - def set_config(self, startup_config, private_config=''): - """ - Sets the config files that are pushed to startup-config and - private-config in NVRAM when the instance is started. - - :param startup_config: path to statup-config file - :param private_config: path to private-config file - (keep existing data when if an empty string) - """ - - if self._startup_config != startup_config or self._private_config != private_config: - - self._hypervisor.send("vm set_config {name} {startup} {private}".format(name=self._name, - startup='"' + startup_config + '"', - private='"' + private_config + '"')) - - log.info("router {name} [id={id}]: has a startup-config set: {startup}".format(name=self._name, - id=self._id, - startup='"' + startup_config + '"')) - - self._startup_config = startup_config - - if private_config: - log.info("router {name} [id={id}]: has a private-config set: {private}".format(name=self._name, - id=self._id, - private='"' + private_config + '"')) - - self._private_config = private_config - - def extract_config(self): - """ - Gets the contents of the config files - startup-config and private-config from NVRAM. - - :returns: tuple (startup-config, private-config) base64 encoded - """ - - try: - reply = self._hypervisor.send("vm extract_config {}".format(self._name))[0].rsplit(' ', 2)[-2:] - except IOError: - # for some reason Dynamips gets frozen when it does not find the magic number in the NVRAM file. - return None, None - startup_config = reply[0][1:-1] # get statup-config and remove single quotes - private_config = reply[1][1:-1] # get private-config and remove single quotes - return startup_config, private_config - - def push_config(self, startup_config, private_config='(keep)'): - """ - Pushes configuration to the config files startup-config and private-config in NVRAM. - The data is a Base64 encoded string, or '(keep)' to keep existing data. - - :param startup_config: statup-config string base64 encoded - :param private_config: private-config string base64 encoded - (keep existing data when if the value is ('keep')) - """ - - self._hypervisor.send("vm push_config {name} {startup} {private}".format(name=self._name, - startup=startup_config, - private=private_config)) - - log.info("router {name} [id={id}]: new startup-config pushed".format(name=self._name, - id=self._id)) - - if private_config != '(keep)': - log.info("router {name} [id={id}]: new private-config pushed".format(name=self._name, - id=self._id)) - - def save_configs(self): - """ - Saves the startup-config and private-config to files. - """ - - if self.startup_config or self.private_config: - startup_config_base64, private_config_base64 = self.extract_config() - if startup_config_base64: - try: - config = base64.decodebytes(startup_config_base64.encode("utf-8")).decode("utf-8") - config = "!\n" + config.replace("\r", "") - config_path = os.path.join(self.hypervisor.working_dir, self.startup_config) - with open(config_path, "w") as f: - log.info("saving startup-config to {}".format(self.startup_config)) - f.write(config) - except OSError as e: - raise DynamipsError("Could not save the startup configuration {}: {}".format(config_path, e)) - - if private_config_base64: - try: - config = base64.decodebytes(private_config_base64.encode("utf-8")).decode("utf-8") - config = "!\n" + config.replace("\r", "") - config_path = os.path.join(self.hypervisor.working_dir, self.private_config) - with open(config_path, "w") as f: - log.info("saving private-config to {}".format(self.private_config)) - f.write(config) - except OSError as e: - raise DynamipsError("Could not save the private configuration {}: {}".format(config_path, e)) - - @property - def ram(self): - """ - Returns the amount of RAM allocated to this router. - - :returns: amount of RAM in Mbytes (integer) - """ - - return self._ram - - @ram.setter - def ram(self, ram): - """ - Sets amount of RAM allocated to this router - - :param ram: amount of RAM in Mbytes (integer) - """ - - if self._ram == ram: - return - - self._hypervisor.send("vm set_ram {name} {ram}".format(name=self._name, - ram=ram)) - - log.info("router {name} [id={id}]: RAM updated from {old_ram}MB to {new_ram}MB".format(name=self._name, - id=self._id, - old_ram=self._ram, - new_ram=ram)) - - self._hypervisor.decrease_memory_load(self._ram) - self._ram = ram - self._hypervisor.increase_memory_load(ram) - - @property - def nvram(self): - """ - Returns the mount of NVRAM allocated to this router. - - :returns: amount of NVRAM in Kbytes (integer) - """ - - return self._nvram - - @nvram.setter - def nvram(self, nvram): - """ - Sets amount of NVRAM allocated to this router - - :param nvram: amount of NVRAM in Kbytes (integer) - """ - - if self._nvram == nvram: - return - - self._hypervisor.send("vm set_nvram {name} {nvram}".format(name=self._name, - nvram=nvram)) - - log.info("router {name} [id={id}]: NVRAM updated from {old_nvram}KB to {new_nvram}KB".format(name=self._name, - id=self._id, - old_nvram=self._nvram, - new_nvram=nvram)) - self._nvram = nvram - - @property - def mmap(self): - """ - Returns True if a mapped file is used to simulate this router memory. - - :returns: boolean either mmap is activated or not - """ - - return self._mmap - - @mmap.setter - def mmap(self, mmap): - """ - Enable/Disable use of a mapped file to simulate router memory. - By default, a mapped file is used. This is a bit slower, but requires less memory. - - :param mmap: activate/deactivate mmap (boolean) - """ - - if mmap: - flag = 1 - else: - flag = 0 - self._hypervisor.send("vm set_ram_mmap {name} {mmap}".format(name=self._name, - mmap=flag)) - - if mmap: - log.info("router {name} [id={id}]: mmap enabled".format(name=self._name, - id=self._id)) - else: - log.info("router {name} [id={id}]: mmap disabled".format(name=self._name, - id=self._id)) - self._mmap = mmap - - @property - def sparsemem(self): - """ - Returns True if sparse memory is used on this router. - - :returns: boolean either mmap is activated or not - """ - - return self._sparsemem - - @sparsemem.setter - def sparsemem(self, sparsemem): - """ - Enable/disable use of sparse memory - - :param sparsemem: activate/deactivate sparsemem (boolean) - """ - - if sparsemem: - flag = 1 - else: - flag = 0 - self._hypervisor.send("vm set_sparse_mem {name} {sparsemem}".format(name=self._name, - sparsemem=flag)) - - if sparsemem: - log.info("router {name} [id={id}]: sparse memory enabled".format(name=self._name, - id=self._id)) - else: - log.info("router {name} [id={id}]: sparse memory disabled".format(name=self._name, - id=self._id)) - self._sparsemem = sparsemem - - @property - def clock_divisor(self): - """ - Returns the clock divisor value for this router. - - :returns: clock divisor value (integer) - """ - - return self._clock_divisor - - @clock_divisor.setter - def clock_divisor(self, clock_divisor): - """ - Sets the clock divisor value. The higher is the value, the faster is the clock in the - virtual machine. The default is 4, but it is often required to adjust it. - - :param clock_divisor: clock divisor value (integer) - """ - - self._hypervisor.send("vm set_clock_divisor {name} {clock}".format(name=self._name, - clock=clock_divisor)) - - log.info("router {name} [id={id}]: clock divisor updated from {old_clock} to {new_clock}".format(name=self._name, - id=self._id, - old_clock=self._clock_divisor, - new_clock=clock_divisor)) - self._clock_divisor = clock_divisor - - @property - def idlepc(self): - """ - Returns the idle Pointer Counter (PC). - - :returns: idlepc value (string) - """ - - return self._idlepc - - @idlepc.setter - def idlepc(self, idlepc): - """ - Sets the idle Pointer Counter (PC) - - :param idlepc: idlepc value (string) - """ - - if not idlepc: - idlepc = "0x0" - - if not self.is_running(): - # router is not running - self._hypervisor.send("vm set_idle_pc {name} {idlepc}".format(name=self._name, - idlepc=idlepc)) - else: - self._hypervisor.send("vm set_idle_pc_online {name} 0 {idlepc}".format(name=self._name, - idlepc=idlepc)) - - log.info("router {name} [id={id}]: idle-PC set to {idlepc}".format(name=self._name, - id=self._id, - idlepc=idlepc)) - - self._idlepc = idlepc - - def get_idle_pc_prop(self): - """ - Gets the idle PC proposals. - Takes 1000 measurements and records up to 10 idle PC proposals. - There is a 10ms wait between each measurement. - - :returns: list of idle PC proposal - """ - - if not self.is_running(): - # router is not running - raise DynamipsError("router {name} is not running".format(name=self._name)) - - log.info("router {name} [id={id}] has started calculating Idle-PC values".format(name=self._name, id=self._id)) - begin = time.time() - idlepcs = self._hypervisor.send("vm get_idle_pc_prop {} 0".format(self._name)) - log.info("router {name} [id={id}] has finished calculating Idle-PC values after {time:.4f} seconds".format(name=self._name, - id=self._id, - time=time.time() - begin)) - return idlepcs - - def show_idle_pc_prop(self): - """ - Dumps the idle PC proposals (previously generated). - - :returns: list of idle PC proposal - """ - - if not self.is_running(): - # router is not running - raise DynamipsError("router {name} is not running".format(name=self._name)) - - return self._hypervisor.send("vm show_idle_pc_prop {} 0".format(self._name)) - - @property - def idlemax(self): - """ - Returns CPU idle max value. - - :returns: idle max (integer) - """ - - return self._idlemax - - @idlemax.setter - def idlemax(self, idlemax): - """ - Sets CPU idle max value - - :param idlemax: idle max value (integer) - """ - - if self.is_running(): # router is running - self._hypervisor.send("vm set_idle_max {name} 0 {idlemax}".format(name=self._name, - idlemax=idlemax)) - - log.info("router {name} [id={id}]: idlemax updated from {old_idlemax} to {new_idlemax}".format(name=self._name, - id=self._id, - old_idlemax=self._idlemax, - new_idlemax=idlemax)) - - self._idlemax = idlemax - - @property - def idlesleep(self): - """ - Returns CPU idle sleep time value. - - :returns: idle sleep (integer) - """ - - return self._idlesleep - - @idlesleep.setter - def idlesleep(self, idlesleep): - """ - Sets CPU idle sleep time value. - - :param idlesleep: idle sleep value (integer) - """ - - if self.is_running(): # router is running - self._hypervisor.send("vm set_idle_sleep_time {name} 0 {idlesleep}".format(name=self._name, - idlesleep=idlesleep)) - - log.info("router {name} [id={id}]: idlesleep updated from {old_idlesleep} to {new_idlesleep}".format(name=self._name, - id=self._id, - old_idlesleep=self._idlesleep, - new_idlesleep=idlesleep)) - - self._idlesleep = idlesleep - - def show_timer_drift(self): - """ - Shows info about potential timer drift. - - :returns: timer drift info. - """ - - return self._hypervisor.send("vm show_timer_drift {} 0".format(self._name)) - - @property - def ghost_file(self): - """ - Returns ghost RAM file. - - :returns: path to ghost file - """ - - return self._ghost_file - - @ghost_file.setter - def ghost_file(self, ghost_file): - """ - Sets ghost RAM file - - :ghost_file: path to ghost file - """ - - self._hypervisor.send("vm set_ghost_file {name} {ghost_file}".format(name=self._name, - ghost_file=ghost_file)) - - log.info("router {name} [id={id}]: ghost file set to {ghost_file}".format(name=self._name, - id=self._id, - ghost_file=ghost_file)) - - self._ghost_file = ghost_file - - # if this is a ghost instance, track this as a hosted ghost instance by this hypervisor - if self.ghost_status == 1: - self._hypervisor.add_ghost(ghost_file, self) - - def formatted_ghost_file(self): - """ - Returns a properly formatted ghost file name. - - :returns: formatted ghost_file name (string) - """ - - # replace specials characters in 'drive:\filename' in Linux and Dynamips in MS Windows or viceversa. - ghost_file = "{}-{}.ghost".format(os.path.basename(self._image), self._ram) - ghost_file = ghost_file.replace('\\', '-').replace('/', '-').replace(':', '-') - return ghost_file - - @property - def ghost_status(self): - """Returns ghost RAM status - - :returns: ghost status (integer) - """ - - return self._ghost_status - - @ghost_status.setter - def ghost_status(self, ghost_status): - """ - Sets ghost RAM status - - :param ghost_status: state flag indicating status - 0 => Do not use IOS ghosting - 1 => This is a ghost instance - 2 => Use an existing ghost instance - """ - - self._hypervisor.send("vm set_ghost_status {name} {ghost_status}".format(name=self._name, - ghost_status=ghost_status)) - - log.info("router {name} [id={id}]: ghost status set to {ghost_status}".format(name=self._name, - id=self._id, - ghost_status=ghost_status)) - self._ghost_status = ghost_status - - @property - def exec_area(self): - """ - Returns the exec area value. - - :returns: exec area value (integer) - """ - - return self._exec_area - - @exec_area.setter - def exec_area(self, exec_area): - """ - Sets the exec area value. - The exec area is a pool of host memory used to store pages - translated by the JIT (they contain the native code - corresponding to MIPS code pages). - - :param exec_area: exec area value (integer) - """ - - self._hypervisor.send("vm set_exec_area {name} {exec_area}".format(name=self._name, - exec_area=exec_area)) - - log.info("router {name} [id={id}]: exec area updated from {old_exec}MB to {new_exec}MB".format(name=self._name, - id=self._id, - old_exec=self._exec_area, - new_exec=exec_area)) - self._exec_area = exec_area - - @property - def disk0(self): - """ - Returns the size (MB) for PCMCIA disk0. - - :returns: disk0 size (integer) - """ - - return self._disk0 - - @disk0.setter - def disk0(self, disk0): - """ - Sets the size (MB) for PCMCIA disk0. - - :param disk0: disk0 size (integer) - """ - - self._hypervisor.send("vm set_disk0 {name} {disk0}".format(name=self._name, - disk0=disk0)) - - log.info("router {name} [id={id}]: disk0 updated from {old_disk0}MB to {new_disk0}MB".format(name=self._name, - id=self._id, - old_disk0=self._disk0, - new_disk0=disk0)) - self._disk0 = disk0 - - @property - def disk1(self): - """ - Returns the size (MB) for PCMCIA disk1. - - :returns: disk1 size (integer) - """ - - return self._disk1 - - @disk1.setter - def disk1(self, disk1): - """ - Sets the size (MB) for PCMCIA disk1. - - :param disk1: disk1 size (integer) - """ - - self._hypervisor.send("vm set_disk1 {name} {disk1}".format(name=self._name, - disk1=disk1)) - - log.info("router {name} [id={id}]: disk1 updated from {old_disk1}MB to {new_disk1}MB".format(name=self._name, - id=self._id, - old_disk1=self._disk1, - new_disk1=disk1)) - self._disk1 = disk1 - - @property - def confreg(self): - """ - Returns the configuration register. - The default is 0x2102. - - :returns: configuration register value (string) - """ - - return self._confreg - - @confreg.setter - def confreg(self, confreg): - """ - Sets the configuration register. - - :param confreg: configuration register value (string) - """ - - self._hypervisor.send("vm set_conf_reg {name} {confreg}".format(name=self._name, - confreg=confreg)) - - log.info("router {name} [id={id}]: confreg updated from {old_confreg} to {new_confreg}".format(name=self._name, - id=self._id, - old_confreg=self._confreg, - new_confreg=confreg)) - self._confreg = confreg - - @property - def console(self): - """ - Returns the TCP console port. - - :returns: console port (integer) - """ - - return self._console - - @console.setter - def console(self, console): - """ - Sets the TCP console port. - - :param console: console port (integer) - """ - - if console == self._console: - return - - if console in self._allocated_console_ports: - raise DynamipsError("Console port {} is already used by another router".format(console)) - - self._hypervisor.send("vm set_con_tcp_port {name} {console}".format(name=self._name, - console=console)) - - log.info("router {name} [id={id}]: console port updated from {old_console} to {new_console}".format(name=self._name, - id=self._id, - old_console=self._console, - new_console=console)) - self._allocated_console_ports.remove(self._console) - self._console = console - self._allocated_console_ports.append(self._console) - - @property - def aux(self): - """ - Returns the TCP auxiliary port. - - :returns: console auxiliary port (integer) - """ - - return self._aux - - @aux.setter - def aux(self, aux): - """ - Sets the TCP auxiliary port. - - :param aux: console auxiliary port (integer) - """ - - if aux == self._aux: - return - - if aux in self._allocated_aux_ports: - raise DynamipsError("Auxiliary console port {} is already used by another router".format(aux)) - - self._hypervisor.send("vm set_aux_tcp_port {name} {aux}".format(name=self._name, - aux=aux)) - - log.info("router {name} [id={id}]: aux port updated from {old_aux} to {new_aux}".format(name=self._name, - id=self._id, - old_aux=self._aux, - new_aux=aux)) - - self._allocated_aux_ports.remove(self._aux) - self._aux = aux - self._allocated_aux_ports.append(self._aux) - - def get_cpu_info(self, cpu_id=0): - """ - Shows info about the CPU identified by cpu_id. - The boot CPU (which is typically the only CPU) has ID 0. - - :returns: ? (could not test) - """ - - # FIXME: nothing returned by Dynamips. - return self._hypervisor.send("vm cpu_info {name} {cpu_id}".format(name=self._name, - cpu_id=cpu_id)) - - def get_cpu_usage(self, cpu_id=0): - """ - Shows cpu usage in seconds, "cpu_id" is ignored. - - :returns: cpu usage in seconds - """ - - return int(self._hypervisor.send("vm cpu_usage {name} {cpu_id}".format(name=self._name, - cpu_id=cpu_id))[0]) - - def send_console_msg(self, message): - """ - Sends a message to the console. - - :param message: message to send to the console - """ - - self._hypervisor.send("vm send_con_msg {name} {message}".format(name=self._name, - message=message)) - - def send_aux_msg(self, message): - """ - Sends a message to the auxiliary console. - - :param message: message to send to the auxiliary console - """ - - self._hypervisor.send("vm send_aux_msg {name} {message}".format(name=self._name, - message=message)) - - @property - def mac_addr(self): - """ - Returns the MAC address. - - :returns: the MAC address (hexadecimal format: hh:hh:hh:hh:hh:hh) - """ - - return self._mac_addr - - @mac_addr.setter - def mac_addr(self, mac_addr): - """ - Sets the MAC address. - - :param mac_addr: a MAC address (hexadecimal format: hh:hh:hh:hh:hh:hh) - """ - - self._hypervisor.send("{platform} set_mac_addr {name} {mac_addr}".format(platform=self._platform, - name=self._name, - mac_addr=mac_addr)) - - log.info("router {name} [id={id}]: MAC address updated from {old_mac} to {new_mac}".format(name=self._name, - id=self._id, - old_mac=self._mac_addr, - new_mac=mac_addr)) - self._mac_addr = mac_addr - - @property - def system_id(self): - """ - Returns the system ID. - - :returns: the system ID (also called board processor ID) - """ - - return self._system_id - - @system_id.setter - def system_id(self, system_id): - """ - Sets the system ID. - - :param system_id: a system ID (also called board processor ID) - """ - - self._hypervisor.send("{platform} set_system_id {name} {system_id}".format(platform=self._platform, - name=self._name, - system_id=system_id)) - - log.info("router {name} [id={id}]: system ID updated from {old_id} to {new_id}".format(name=self._name, - id=self._id, - old_id=self._system_id, - new_id=system_id)) - self._system_id = system_id - - def get_hardware_info(self): - """ - Get some hardware info about this router. - - :returns: ? (could not test) - """ - - # FIXME: nothing returned by Dynamips. - return (self._hypervisor.send("{platform} show_hardware {name}".format(platform=self._platform, - name=self._name))) - - def get_cpu_usage(self): - """ - Returns the CPU usage. - - :return: CPU usage in percent - """ - - return int(self._hypervisor.send("vm cpu_usage {name} 0".format(name=self._name))[0]) - - def get_slot_bindings(self): - """ - Returns slot bindings. - - :returns: slot bindings (adapter names) list - """ - - return self._hypervisor.send("vm slot_bindings {}".format(self._name)) - - def slot_add_binding(self, slot_id, adapter): - """ - Adds a slot binding (a module into a slot). - - :param slot_id: slot ID - :param adapter: device to add in the corresponding slot - """ - - try: - slot = self._slots[slot_id] - except IndexError: - raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name, - slot_id=slot_id)) - - if slot is not None: - current_adapter = slot - raise DynamipsError("Slot {slot_id} is already occupied by adapter {adapter} on router {name}".format(name=self._name, - slot_id=slot_id, - adapter=current_adapter)) - - # Only c7200, c3600 and c3745 (NM-4T only) support new adapter while running - if self.is_running() and not ((self._platform == 'c7200' and not str(adapter).startswith('C7200')) - and not (self._platform == 'c3600' and self.chassis == '3660') - and not (self._platform == 'c3745' and adapter == 'NM-4T')): - raise DynamipsError("Adapter {adapter} cannot be added while router {name} is running".format(adapter=adapter, - name=self._name)) - - self._hypervisor.send("vm slot_add_binding {name} {slot_id} 0 {adapter}".format(name=self._name, - slot_id=slot_id, - adapter=adapter)) - - log.info("router {name} [id={id}]: adapter {adapter} inserted into slot {slot_id}".format(name=self._name, - id=self._id, - adapter=adapter, - slot_id=slot_id)) - - self._slots[slot_id] = adapter - - # Generate an OIR event if the router is running - if self.is_running(): - - self._hypervisor.send("vm slot_oir_start {name} {slot_id} 0".format(name=self._name, - slot_id=slot_id)) - - log.info("router {name} [id={id}]: OIR start event sent to slot {slot_id}".format(name=self._name, - id=self._id, - slot_id=slot_id)) - - def slot_remove_binding(self, slot_id): - """ - Removes a slot binding (a module from a slot). - - :param slot_id: slot ID - """ - - try: - adapter = self._slots[slot_id] - except IndexError: - raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name, - slot_id=slot_id)) - - if adapter is None: - raise DynamipsError("No adapter in slot {slot_id} on router {name}".format(name=self._name, - slot_id=slot_id)) - - # Only c7200, c3600 and c3745 (NM-4T only) support to remove adapter while running - if self.is_running() and not ((self._platform == 'c7200' and not str(adapter).startswith('C7200')) - and not (self._platform == 'c3600' and self.chassis == '3660') - and not (self._platform == 'c3745' and adapter == 'NM-4T')): - raise DynamipsError("Adapter {adapter} cannot be removed while router {name} is running".format(adapter=adapter, - name=self._name)) - - # Generate an OIR event if the router is running - if self.is_running(): - - self._hypervisor.send("vm slot_oir_stop {name} {slot_id} 0".format(name=self._name, - slot_id=slot_id)) - - log.info("router {name} [id={id}]: OIR stop event sent to slot {slot_id}".format(name=self._name, - id=self._id, - slot_id=slot_id)) - - self._hypervisor.send("vm slot_remove_binding {name} {slot_id} 0".format(name=self._name, - slot_id=slot_id)) - - log.info("router {name} [id={id}]: adapter {adapter} removed from slot {slot_id}".format(name=self._name, - id=self._id, - adapter=adapter, - slot_id=slot_id)) - self._slots[slot_id] = None - - def install_wic(self, wic_slot_id, wic): - """ - Installs a WIC adapter into this router. - - :param wic_slot_id: WIC slot ID - :param wic: WIC to be installed - """ - - # WICs are always installed on adapters in slot 0 - slot_id = 0 - - # Do not check if slot has an adapter because adapters with WICs interfaces - # must be inserted by default in the router and cannot be removed. - adapter = self._slots[slot_id] - - if wic_slot_id > len(adapter.wics) - 1: - raise DynamipsError("WIC slot {wic_slot_id} doesn't exist".format(name=self._name, - wic_slot_id=wic_slot_id)) - - if not adapter.wic_slot_available(wic_slot_id): - raise DynamipsError("WIC slot {wic_slot_id} is already occupied by another WIC".format(name=self._name, - wic_slot_id=wic_slot_id)) - - # Dynamips WICs slot IDs start on a multiple of 16 - # WIC1 = 16, WIC2 = 32 and WIC3 = 48 - internal_wic_slot_id = 16 * (wic_slot_id + 1) - self._hypervisor.send("vm slot_add_binding {name} {slot_id} {wic_slot_id} {wic}".format(name=self._name, - slot_id=slot_id, - wic_slot_id=internal_wic_slot_id, - wic=wic)) - - log.info("router {name} [id={id}]: {wic} inserted into WIC slot {wic_slot_id}".format(name=self._name, - id=self._id, - wic=wic, - wic_slot_id=wic_slot_id)) - - adapter.install_wic(wic_slot_id, wic) - - def uninstall_wic(self, wic_slot_id): - """ - Uninstalls a WIC adapter from this router. - - :param wic_slot_id: WIC slot ID - """ - - # WICs are always installed on adapters in slot 0 - slot_id = 0 - - # Do not check if slot has an adapter because adapters with WICs interfaces - # must be inserted by default in the router and cannot be removed. - adapter = self._slots[slot_id] - - if wic_slot_id > len(adapter.wics) - 1: - raise DynamipsError("WIC slot {wic_slot_id} doesn't exist".format(name=self._name, - wic_slot_id=wic_slot_id)) - - if adapter.wic_slot_available(wic_slot_id): - raise DynamipsError("No WIC is installed in WIC slot {wic_slot_id}".format(name=self._name, - wic_slot_id=wic_slot_id)) - # Dynamips WICs slot IDs start on a multiple of 16 - # WIC1 = 16, WIC2 = 32 and WIC3 = 48 - internal_wic_slot_id = 16 * (wic_slot_id + 1) - self._hypervisor.send("vm slot_remove_binding {name} {slot_id} {wic_slot_id}".format(name=self._name, - slot_id=slot_id, - wic_slot_id=internal_wic_slot_id)) - - log.info("router {name} [id={id}]: {wic} removed from WIC slot {wic_slot_id}".format(name=self._name, - id=self._id, - wic=adapter.wics[wic_slot_id], - wic_slot_id=wic_slot_id)) - adapter.uninstall_wic(wic_slot_id) - - def get_slot_nio_bindings(self, slot_id): - """ - Returns slot NIO bindings. - - :param slot_id: slot ID - - :returns: list of NIO bindings - """ - - return (self._hypervisor.send("vm slot_nio_bindings {name} {slot_id}".format(name=self._name, - slot_id=slot_id))) - - def slot_add_nio_binding(self, slot_id, port_id, nio): - """ - Adds a slot NIO binding. - - :param slot_id: slot ID - :param port_id: port ID - :param nio: NIO instance to add to the slot/port - """ - - try: - adapter = self._slots[slot_id] - except IndexError: - raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name, - slot_id=slot_id)) - if not adapter.port_exists(port_id): - raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter, - port_id=port_id)) - - self._hypervisor.send("vm slot_add_nio_binding {name} {slot_id} {port_id} {nio}".format(name=self._name, - slot_id=slot_id, - port_id=port_id, - nio=nio)) - - log.info("router {name} [id={id}]: NIO {nio_name} bound to port {slot_id}/{port_id}".format(name=self._name, - id=self._id, - nio_name=nio.name, - slot_id=slot_id, - port_id=port_id)) - - self.slot_enable_nio(slot_id, port_id) - adapter.add_nio(port_id, nio) - - def slot_remove_nio_binding(self, slot_id, port_id): - """ - Removes a slot NIO binding. - - :param slot_id: slot ID - :param port_id: port ID - - :returns: removed NIO instance - """ - - try: - adapter = self._slots[slot_id] - except IndexError: - raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name, - slot_id=slot_id)) - if not adapter.port_exists(port_id): - raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter, - port_id=port_id)) - - self.slot_disable_nio(slot_id, port_id) - self._hypervisor.send("vm slot_remove_nio_binding {name} {slot_id} {port_id}".format(name=self._name, - slot_id=slot_id, - port_id=port_id)) - - nio = adapter.get_nio(port_id) - adapter.remove_nio(port_id) - - log.info("router {name} [id={id}]: NIO {nio_name} removed from port {slot_id}/{port_id}".format(name=self._name, - id=self._id, - nio_name=nio.name, - slot_id=slot_id, - port_id=port_id)) - - return nio - - def slot_enable_nio(self, slot_id, port_id): - """ - Enables a slot NIO binding. - - :param slot_id: slot ID - :param port_id: port ID - """ - - if self.is_running(): # running router - self._hypervisor.send("vm slot_enable_nio {name} {slot_id} {port_id}".format(name=self._name, - slot_id=slot_id, - port_id=port_id)) - - log.info("router {name} [id={id}]: NIO enabled on port {slot_id}/{port_id}".format(name=self._name, - id=self._id, - slot_id=slot_id, - port_id=port_id)) - - def slot_disable_nio(self, slot_id, port_id): - """ - Disables a slot NIO binding. - - :param slot_id: slot ID - :param port_id: port ID - """ - - if self.is_running(): # running router - self._hypervisor.send("vm slot_disable_nio {name} {slot_id} {port_id}".format(name=self._name, - slot_id=slot_id, - port_id=port_id)) - - log.info("router {name} [id={id}]: NIO disabled on port {slot_id}/{port_id}".format(name=self._name, - id=self._id, - slot_id=slot_id, - port_id=port_id)) - - def start_capture(self, slot_id, port_id, output_file, data_link_type="DLT_EN10MB"): - """ - Starts a packet capture. - - :param slot_id: slot ID - :param port_id: port ID - :param output_file: PCAP destination file for the capture - :param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB - """ - - try: - adapter = self._slots[slot_id] - except IndexError: - raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name, - slot_id=slot_id)) - if not adapter.port_exists(port_id): - raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter, - port_id=port_id)) - - data_link_type = data_link_type.lower() - if data_link_type.startswith("dlt_"): - data_link_type = data_link_type[4:] - - nio = adapter.get_nio(port_id) - - if nio.input_filter[0] is not None and nio.output_filter[0] is not None: - raise DynamipsError("Port {port_id} has already a filter applied on {adapter}".format(adapter=adapter, - port_id=port_id)) - - 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("router {name} [id={id}]: starting packet capture on port {slot_id}/{port_id}".format(name=self._name, - id=self._id, - nio_name=nio.name, - slot_id=slot_id, - port_id=port_id)) - - def stop_capture(self, slot_id, port_id): - """ - Stops a packet capture. - - :param slot_id: slot ID - :param port_id: port ID - """ - - try: - adapter = self._slots[slot_id] - except IndexError: - raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name, - slot_id=slot_id)) - if not adapter.port_exists(port_id): - raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter, - port_id=port_id)) - - nio = adapter.get_nio(port_id) - nio.unbind_filter("both") - - log.info("router {name} [id={id}]: stopping packet capture on port {slot_id}/{port_id}".format(name=self._name, - id=self._id, - nio_name=nio.name, - slot_id=slot_id, - port_id=port_id)) - - def _create_slots(self, numslots): - """ - Creates the appropriate number of slots for this router. - - :param numslots: number of slots to create - """ - - self._slots = numslots * [None] - - @property - def slots(self): - """ - Returns the slots for this router. - - :return: slot list - """ - - return self._slots diff --git a/gns3server/old_modules/dynamips/schemas/__init__.py b/gns3server/old_modules/dynamips/schemas/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/gns3server/old_modules/dynamips/schemas/atmsw.py b/gns3server/old_modules/dynamips/schemas/atmsw.py deleted file mode 100644 index 37669478..00000000 --- a/gns3server/old_modules/dynamips/schemas/atmsw.py +++ /dev/null @@ -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 . - -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"] -} diff --git a/gns3server/old_modules/dynamips/schemas/ethhub.py b/gns3server/old_modules/dynamips/schemas/ethhub.py deleted file mode 100644 index 1002a696..00000000 --- a/gns3server/old_modules/dynamips/schemas/ethhub.py +++ /dev/null @@ -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 . - -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"] -} diff --git a/gns3server/old_modules/dynamips/schemas/ethsw.py b/gns3server/old_modules/dynamips/schemas/ethsw.py deleted file mode 100644 index 33559f28..00000000 --- a/gns3server/old_modules/dynamips/schemas/ethsw.py +++ /dev/null @@ -1,348 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2014 GNS3 Technologies Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -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"] -} diff --git a/gns3server/old_modules/dynamips/schemas/frsw.py b/gns3server/old_modules/dynamips/schemas/frsw.py deleted file mode 100644 index 835e47a7..00000000 --- a/gns3server/old_modules/dynamips/schemas/frsw.py +++ /dev/null @@ -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 . - -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"] -} diff --git a/gns3server/old_modules/dynamips/schemas/vm.py b/gns3server/old_modules/dynamips/schemas/vm.py deleted file mode 100644 index adb380e4..00000000 --- a/gns3server/old_modules/dynamips/schemas/vm.py +++ /dev/null @@ -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 . - -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"] -} diff --git a/gns3server/schemas/dynamips.py b/gns3server/schemas/dynamips.py new file mode 100644 index 00000000..a707d0cc --- /dev/null +++ b/gns3server/schemas/dynamips.py @@ -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 . + + +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"] +}