diff --git a/docs/api/examples/post_project.txt b/docs/api/examples/post_project.txt index 6d61c41f..3a99e4e6 100644 --- a/docs/api/examples/post_project.txt +++ b/docs/api/examples/post_project.txt @@ -1,8 +1,8 @@ -curl -i -X POST 'http://localhost:8000/project' -d '{"location": "/private/var/folders/3s/r2wbv07n7wg4vrsn874lmxxh0000gn/T/pytest-301/test_create_project_with_dir0"}' +curl -i -X POST 'http://localhost:8000/project' -d '{"location": "/private/var/folders/3s/r2wbv07n7wg4vrsn874lmxxh0000gn/T/pytest-308/test_create_project_with_dir0"}' POST /project HTTP/1.1 { - "location": "/private/var/folders/3s/r2wbv07n7wg4vrsn874lmxxh0000gn/T/pytest-301/test_create_project_with_dir0" + "location": "/private/var/folders/3s/r2wbv07n7wg4vrsn874lmxxh0000gn/T/pytest-308/test_create_project_with_dir0" } @@ -15,6 +15,6 @@ SERVER: Python/3.4 aiohttp/0.13.1 X-ROUTE: /project { - "location": "/private/var/folders/3s/r2wbv07n7wg4vrsn874lmxxh0000gn/T/pytest-301/test_create_project_with_dir0", - "uuid": "d4d66c3f-439b-4ae9-972b-59040189c995" + "location": "/private/var/folders/3s/r2wbv07n7wg4vrsn874lmxxh0000gn/T/pytest-308/test_create_project_with_dir0", + "uuid": "7b9efb50-4909-4dc2-bb61-0bf443874c4c" } diff --git a/gns3server/modules/old_vpcs/__init__.py b/gns3server/modules/old_vpcs/__init__.py deleted file mode 100644 index aa0f216e..00000000 --- a/gns3server/modules/old_vpcs/__init__.py +++ /dev/null @@ -1,652 +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 . - -""" -VPCS server module. -""" - -import os -import base64 -import socket -import shutil - -from gns3server.modules import IModule -from gns3server.config import Config -from .vpcs_device import VPCSDevice -from .vpcs_error import VPCSError -from .nios.nio_udp import NIO_UDP -from .nios.nio_tap import NIO_TAP -from ..attic import find_unused_port - -from .schemas import VPCS_CREATE_SCHEMA -from .schemas import VPCS_DELETE_SCHEMA -from .schemas import VPCS_UPDATE_SCHEMA -from .schemas import VPCS_START_SCHEMA -from .schemas import VPCS_STOP_SCHEMA -from .schemas import VPCS_RELOAD_SCHEMA -from .schemas import VPCS_ALLOCATE_UDP_PORT_SCHEMA -from .schemas import VPCS_ADD_NIO_SCHEMA -from .schemas import VPCS_DELETE_NIO_SCHEMA -from .schemas import VPCS_EXPORT_CONFIG_SCHEMA - -import logging -log = logging.getLogger(__name__) - - -class VPCS(IModule): - """ - VPCS 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 VPCS location - config = Config.instance() - vpcs_config = config.get_section_config(name.upper()) - self._vpcs = vpcs_config.get("vpcs_path") - if not self._vpcs or not os.path.isfile(self._vpcs): - paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep) - # look for VPCS in the current working directory and $PATH - for path in paths: - try: - if "vpcs" in os.listdir(path) and os.access(os.path.join(path, "vpcs"), os.X_OK): - self._vpcs = os.path.join(path, "vpcs") - break - except OSError: - continue - - if not self._vpcs: - log.warning("VPCS binary couldn't be found!") - elif not os.access(self._vpcs, os.X_OK): - log.warning("VPCS is not executable") - - # a new process start when calling IModule - IModule.__init__(self, name, *args, **kwargs) - self._vpcs_instances = {} - self._console_start_port_range = vpcs_config.get("console_start_port_range", 4501) - self._console_end_port_range = vpcs_config.get("console_end_port_range", 5000) - self._allocated_udp_ports = [] - self._udp_start_port_range = vpcs_config.get("udp_start_port_range", 20501) - self._udp_end_port_range = vpcs_config.get("udp_end_port_range", 21000) - self._host = vpcs_config.get("host", kwargs["host"]) - self._console_host = vpcs_config.get("console_host", kwargs["console_host"]) - self._projects_dir = kwargs["projects_dir"] - self._tempdir = kwargs["temp_dir"] - self._working_dir = self._projects_dir - - def stop(self, signum=None): - """ - Properly stops the module. - - :param signum: signal number (if called by the signal handler) - """ - - # delete all VPCS instances - for vpcs_id in self._vpcs_instances: - vpcs_instance = self._vpcs_instances[vpcs_id] - vpcs_instance.delete() - - IModule.stop(self, signum) # this will stop the I/O loop - - def get_vpcs_instance(self, vpcs_id): - """ - Returns a VPCS device instance. - - :param vpcs_id: VPCS device identifier - - :returns: VPCSDevice instance - """ - - if vpcs_id not in self._vpcs_instances: - log.debug("VPCS device ID {} doesn't exist".format(vpcs_id), exc_info=1) - self.send_custom_error("VPCS device ID {} doesn't exist".format(vpcs_id)) - return None - return self._vpcs_instances[vpcs_id] - - @IModule.route("vpcs.reset") - def reset(self, request): - """ - Resets the module. - - :param request: JSON request - """ - - # delete all vpcs instances - for vpcs_id in self._vpcs_instances: - vpcs_instance = self._vpcs_instances[vpcs_id] - vpcs_instance.delete() - - # resets the instance IDs - VPCSDevice.reset() - - self._vpcs_instances.clear() - self._allocated_udp_ports.clear() - - self._working_dir = self._projects_dir - log.info("VPCS module has been reset") - - @IModule.route("vpcs.settings") - def settings(self, request): - """ - Set or update settings. - - Optional request parameters: - - path (path to vpcs) - - working_dir (path to a working directory) - - project_name - - console_start_port_range - - console_end_port_range - - udp_start_port_range - - udp_end_port_range - - :param request: JSON request - """ - - if request is None: - self.send_param_error() - return - - if "path" in request and request["path"]: - self._vpcs = request["path"] - log.info("VPCS path set to {}".format(self._vpcs)) - for vpcs_id in self._vpcs_instances: - vpcs_instance = self._vpcs_instances[vpcs_id] - vpcs_instance.path = self._vpcs - - if "working_dir" in request: - new_working_dir = request["working_dir"] - log.info("this server is local with working directory path to {}".format(new_working_dir)) - else: - new_working_dir = os.path.join(self._projects_dir, request["project_name"]) - log.info("this server is remote with working directory path to {}".format(new_working_dir)) - if self._projects_dir != self._working_dir != new_working_dir: - if not os.path.isdir(new_working_dir): - try: - 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 - - # update the working directory if it has changed - if self._working_dir != new_working_dir: - self._working_dir = new_working_dir - for vpcs_id in self._vpcs_instances: - vpcs_instance = self._vpcs_instances[vpcs_id] - vpcs_instance.working_dir = os.path.join(self._working_dir, "vpcs", "pc-{}".format(vpcs_instance.id)) - - if "console_start_port_range" in request and "console_end_port_range" in request: - self._console_start_port_range = request["console_start_port_range"] - self._console_end_port_range = request["console_end_port_range"] - - if "udp_start_port_range" in request and "udp_end_port_range" in request: - self._udp_start_port_range = request["udp_start_port_range"] - self._udp_end_port_range = request["udp_end_port_range"] - - log.debug("received request {}".format(request)) - - @IModule.route("vpcs.create") - def vpcs_create(self, request): - """ - Creates a new VPCS instance. - - Mandatory request parameters: - - name (VPCS name) - - Optional request parameters: - - console (VPCS console port) - - Response parameters: - - id (VPCS instance identifier) - - name (VPCS name) - - default settings - - :param request: JSON request - """ - - # validate the request - if not self.validate_request(request, VPCS_CREATE_SCHEMA): - return - - name = request["name"] - console = request.get("console") - vpcs_id = request.get("vpcs_id") - - try: - - if not self._vpcs: - raise VPCSError("No path to a VPCS executable has been set") - - vpcs_instance = VPCSDevice(name, - self._vpcs, - self._working_dir, - vpcs_id, - console, - self._console_host, - self._console_start_port_range, - self._console_end_port_range) - - except VPCSError as e: - self.send_custom_error(str(e)) - return - - response = {"name": vpcs_instance.name, - "id": vpcs_instance.id} - - defaults = vpcs_instance.defaults() - response.update(defaults) - self._vpcs_instances[vpcs_instance.id] = vpcs_instance - self.send_response(response) - - @IModule.route("vpcs.delete") - def vpcs_delete(self, request): - """ - Deletes a VPCS instance. - - Mandatory request parameters: - - id (VPCS instance identifier) - - Response parameter: - - True on success - - :param request: JSON request - """ - - # validate the request - if not self.validate_request(request, VPCS_DELETE_SCHEMA): - return - - # get the instance - vpcs_instance = self.get_vpcs_instance(request["id"]) - if not vpcs_instance: - return - - try: - vpcs_instance.clean_delete() - del self._vpcs_instances[request["id"]] - except VPCSError as e: - self.send_custom_error(str(e)) - return - - self.send_response(True) - - @IModule.route("vpcs.update") - def vpcs_update(self, request): - """ - Updates a VPCS instance - - Mandatory request parameters: - - id (VPCS instance identifier) - - Optional request parameters: - - any setting to update - - script_file_base64 (base64 encoded) - - Response parameters: - - updated settings - - :param request: JSON request - """ - - # validate the request - if not self.validate_request(request, VPCS_UPDATE_SCHEMA): - return - - # get the instance - vpcs_instance = self.get_vpcs_instance(request["id"]) - if not vpcs_instance: - return - - config_path = os.path.join(vpcs_instance.working_dir, "startup.vpc") - try: - if "script_file_base64" in request: - # a new startup-config has been pushed - config = base64.decodebytes(request["script_file_base64"].encode("utf-8")).decode("utf-8") - config = config.replace("\r", "") - config = config.replace('%h', vpcs_instance.name) - try: - with open(config_path, "w") as f: - log.info("saving script file to {}".format(config_path)) - f.write(config) - except OSError as e: - raise VPCSError("Could not save the configuration {}: {}".format(config_path, e)) - # update the request with the new local startup-config path - request["script_file"] = os.path.basename(config_path) - elif "script_file" in request: - if os.path.isfile(request["script_file"]) and request["script_file"] != config_path: - # this is a local file set in the GUI - try: - with open(request["script_file"], "r", errors="replace") as f: - config = f.read() - with open(config_path, "w") as f: - config = config.replace("\r", "") - config = config.replace('%h', vpcs_instance.name) - f.write(config) - request["script_file"] = os.path.basename(config_path) - except OSError as e: - raise VPCSError("Could not save the configuration from {} to {}: {}".format(request["script_file"], config_path, e)) - elif not os.path.isfile(config_path): - raise VPCSError("Startup-config {} could not be found on this server".format(request["script_file"])) - except VPCSError as e: - self.send_custom_error(str(e)) - return - - # update the VPCS settings - response = {} - for name, value in request.items(): - if hasattr(vpcs_instance, name) and getattr(vpcs_instance, name) != value: - try: - setattr(vpcs_instance, name, value) - response[name] = value - except VPCSError as e: - self.send_custom_error(str(e)) - return - - self.send_response(response) - - @IModule.route("vpcs.start") - def vpcs_start(self, request): - """ - Starts a VPCS instance. - - Mandatory request parameters: - - id (VPCS instance identifier) - - Response parameters: - - True on success - - :param request: JSON request - """ - - # validate the request - if not self.validate_request(request, VPCS_START_SCHEMA): - return - - # get the instance - vpcs_instance = self.get_vpcs_instance(request["id"]) - if not vpcs_instance: - return - - try: - vpcs_instance.start() - except VPCSError as e: - self.send_custom_error(str(e)) - return - self.send_response(True) - - @IModule.route("vpcs.stop") - def vpcs_stop(self, request): - """ - Stops a VPCS instance. - - Mandatory request parameters: - - id (VPCS instance identifier) - - Response parameters: - - True on success - - :param request: JSON request - """ - - # validate the request - if not self.validate_request(request, VPCS_STOP_SCHEMA): - return - - # get the instance - vpcs_instance = self.get_vpcs_instance(request["id"]) - if not vpcs_instance: - return - - try: - vpcs_instance.stop() - except VPCSError as e: - self.send_custom_error(str(e)) - return - self.send_response(True) - - @IModule.route("vpcs.reload") - def vpcs_reload(self, request): - """ - Reloads a VPCS instance. - - Mandatory request parameters: - - id (VPCS identifier) - - Response parameters: - - True on success - - :param request: JSON request - """ - - # validate the request - if not self.validate_request(request, VPCS_RELOAD_SCHEMA): - return - - # get the instance - vpcs_instance = self.get_vpcs_instance(request["id"]) - if not vpcs_instance: - return - - try: - if vpcs_instance.is_running(): - vpcs_instance.stop() - vpcs_instance.start() - except VPCSError as e: - self.send_custom_error(str(e)) - return - self.send_response(True) - - @IModule.route("vpcs.allocate_udp_port") - def allocate_udp_port(self, request): - """ - Allocates a UDP port in order to create an UDP NIO. - - Mandatory request parameters: - - id (VPCS 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, VPCS_ALLOCATE_UDP_PORT_SCHEMA): - return - - # get the instance - vpcs_instance = self.get_vpcs_instance(request["id"]) - if not vpcs_instance: - return - - try: - port = find_unused_port(self._udp_start_port_range, - self._udp_end_port_range, - host=self._host, - socket_type="UDP", - ignore_ports=self._allocated_udp_ports) - except Exception as e: - self.send_custom_error(str(e)) - return - - self._allocated_udp_ports.append(port) - log.info("{} [id={}] has allocated UDP port {} with host {}".format(vpcs_instance.name, - vpcs_instance.id, - port, - self._host)) - - response = {"lport": port, - "port_id": request["port_id"]} - self.send_response(response) - - @IModule.route("vpcs.add_nio") - def add_nio(self, request): - """ - Adds an NIO (Network Input/Output) for a VPCS instance. - - Mandatory request parameters: - - id (VPCS instance identifier) - - 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_tap" - - tap_device (TAP device name e.g. tap0) - - Response parameters: - - port_id (unique port identifier) - - :param request: JSON request - """ - - # validate the request - if not self.validate_request(request, VPCS_ADD_NIO_SCHEMA): - return - - # get the instance - vpcs_instance = self.get_vpcs_instance(request["id"]) - if not vpcs_instance: - return - - port = request["port"] - try: - 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 VPCSError("Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e)) - nio = NIO_UDP(lport, rhost, rport) - elif request["nio"]["type"] == "nio_tap": - tap_device = request["nio"]["tap_device"] - if not self.has_privileged_access(self._vpcs): - raise VPCSError("{} has no privileged access to {}.".format(self._vpcs, tap_device)) - nio = NIO_TAP(tap_device) - if not nio: - raise VPCSError("Requested NIO does not exist or is not supported: {}".format(request["nio"]["type"])) - except VPCSError as e: - self.send_custom_error(str(e)) - return - - try: - vpcs_instance.port_add_nio_binding(port, nio) - except VPCSError as e: - self.send_custom_error(str(e)) - return - - self.send_response({"port_id": request["port_id"]}) - - @IModule.route("vpcs.delete_nio") - def delete_nio(self, request): - """ - Deletes an NIO (Network Input/Output). - - Mandatory request parameters: - - id (VPCS instance identifier) - - port (port identifier) - - Response parameters: - - True on success - - :param request: JSON request - """ - - # validate the request - if not self.validate_request(request, VPCS_DELETE_NIO_SCHEMA): - return - - # get the instance - vpcs_instance = self.get_vpcs_instance(request["id"]) - if not vpcs_instance: - return - - port = request["port"] - try: - nio = vpcs_instance.port_remove_nio_binding(port) - if isinstance(nio, NIO_UDP) and nio.lport in self._allocated_udp_ports: - self._allocated_udp_ports.remove(nio.lport) - except VPCSError as e: - self.send_custom_error(str(e)) - return - - self.send_response(True) - - @IModule.route("vpcs.export_config") - def export_config(self, request): - """ - Exports the script file from a VPCS instance. - - Mandatory request parameters: - - id (vm identifier) - - Response parameters: - - script_file_base64 (script file base64 encoded) - - False if no configuration can be exported - """ - - # validate the request - if not self.validate_request(request, VPCS_EXPORT_CONFIG_SCHEMA): - return - - # get the instance - vpcs_instance = self.get_vpcs_instance(request["id"]) - if not vpcs_instance: - return - - response = {} - script_file_path = os.path.join(vpcs_instance.working_dir, vpcs_instance.script_file) - try: - with open(script_file_path, "rb") as f: - config = f.read() - response["script_file_base64"] = base64.encodebytes(config).decode("utf-8") - except OSError as e: - self.send_custom_error("unable to export the script file: {}".format(e)) - return - - if not response: - self.send_response(False) - else: - self.send_response(response) - - @IModule.route("vpcs.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) diff --git a/gns3server/modules/old_vpcs/adapters/__init__.py b/gns3server/modules/old_vpcs/adapters/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/gns3server/modules/old_vpcs/adapters/adapter.py b/gns3server/modules/old_vpcs/adapters/adapter.py deleted file mode 100644 index cf439427..00000000 --- a/gns3server/modules/old_vpcs/adapters/adapter.py +++ /dev/null @@ -1,104 +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 . - - -class Adapter(object): - """ - Base class for adapters. - - :param interfaces: number of interfaces supported by this adapter. - """ - - def __init__(self, interfaces=1): - - self._interfaces = interfaces - - self._ports = {} - for port_id in range(0, interfaces): - self._ports[port_id] = None - - def removable(self): - """ - Returns True if the adapter can be removed from a slot - and False if not. - - :returns: boolean - """ - - return True - - def port_exists(self, port_id): - """ - Checks if a port exists on this adapter. - - :returns: True is the port exists, - False otherwise. - """ - - if port_id in self._ports: - return True - return False - - def add_nio(self, port_id, nio): - """ - Adds a NIO to a port on this adapter. - - :param port_id: port ID (integer) - :param nio: NIO instance - """ - - self._ports[port_id] = nio - - def remove_nio(self, port_id): - """ - Removes a NIO from a port on this adapter. - - :param port_id: port ID (integer) - """ - - self._ports[port_id] = None - - def get_nio(self, port_id): - """ - Returns the NIO assigned to a port. - - :params port_id: port ID (integer) - - :returns: NIO instance - """ - - return self._ports[port_id] - - @property - def ports(self): - """ - Returns port to NIO mapping - - :returns: dictionary port -> NIO - """ - - return self._ports - - @property - def interfaces(self): - """ - Returns the number of interfaces supported by this adapter. - - :returns: number of interfaces - """ - - return self._interfaces diff --git a/gns3server/modules/old_vpcs/adapters/ethernet_adapter.py b/gns3server/modules/old_vpcs/adapters/ethernet_adapter.py deleted file mode 100644 index bbca7f40..00000000 --- a/gns3server/modules/old_vpcs/adapters/ethernet_adapter.py +++ /dev/null @@ -1,31 +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 . - -from .adapter import Adapter - - -class EthernetAdapter(Adapter): - """ - VPCS Ethernet adapter. - """ - - def __init__(self): - Adapter.__init__(self, interfaces=1) - - def __str__(self): - - return "VPCS Ethernet adapter" diff --git a/gns3server/modules/old_vpcs/nios/__init__.py b/gns3server/modules/old_vpcs/nios/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/gns3server/modules/old_vpcs/nios/nio_tap.py b/gns3server/modules/old_vpcs/nios/nio_tap.py deleted file mode 100644 index 4c3ed6b2..00000000 --- a/gns3server/modules/old_vpcs/nios/nio_tap.py +++ /dev/null @@ -1,46 +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 TAP NIOs (UNIX based OSes only). -""" - - -class NIO_TAP(object): - """ - TAP NIO. - - :param tap_device: TAP device name (e.g. tap0) - """ - - def __init__(self, tap_device): - - self._tap_device = tap_device - - @property - def tap_device(self): - """ - Returns the TAP device used by this NIO. - - :returns: the TAP device name - """ - - return self._tap_device - - def __str__(self): - - return "NIO TAP" diff --git a/gns3server/modules/old_vpcs/nios/nio_udp.py b/gns3server/modules/old_vpcs/nios/nio_udp.py deleted file mode 100644 index 0527f675..00000000 --- a/gns3server/modules/old_vpcs/nios/nio_udp.py +++ /dev/null @@ -1,72 +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 UDP NIOs. -""" - - -class NIO_UDP(object): - """ - UDP NIO. - - :param lport: local port number - :param rhost: remote address/host - :param rport: remote port number - """ - - _instance_count = 0 - - def __init__(self, lport, rhost, rport): - - self._lport = lport - self._rhost = rhost - self._rport = rport - - @property - def lport(self): - """ - Returns the local port - - :returns: local port number - """ - - return self._lport - - @property - def rhost(self): - """ - Returns the remote host - - :returns: remote address/host - """ - - return self._rhost - - @property - def rport(self): - """ - Returns the remote port - - :returns: remote port number - """ - - return self._rport - - def __str__(self): - - return "NIO UDP" diff --git a/gns3server/modules/old_vpcs/schemas.py b/gns3server/modules/old_vpcs/schemas.py deleted file mode 100644 index 6556895b..00000000 --- a/gns3server/modules/old_vpcs/schemas.py +++ /dev/null @@ -1,347 +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 . - - -VPCS_CREATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to create a new VPCS instance", - "type": "object", - "properties": { - "name": { - "description": "VPCS device name", - "type": "string", - "minLength": 1, - }, - "vpcs_id": { - "description": "VPCS device instance ID", - "type": "integer" - }, - "console": { - "description": "console TCP port", - "minimum": 1, - "maximum": 65535, - "type": "integer" - }, - }, - "additionalProperties": False, - "required": ["name"] -} - -VPCS_DELETE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to delete a VPCS instance", - "type": "object", - "properties": { - "id": { - "description": "VPCS device instance ID", - "type": "integer" - }, - }, - "additionalProperties": False, - "required": ["id"] -} - -VPCS_UPDATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to update a VPCS instance", - "type": "object", - "properties": { - "id": { - "description": "VPCS device instance ID", - "type": "integer" - }, - "name": { - "description": "VPCS device name", - "type": "string", - "minLength": 1, - }, - "console": { - "description": "console TCP port", - "minimum": 1, - "maximum": 65535, - "type": "integer" - }, - "script_file": { - "description": "Path to the VPCS script file file", - "type": "string", - "minLength": 1, - }, - "script_file_base64": { - "description": "Script file base64 encoded", - "type": "string" - }, - }, - "additionalProperties": False, - "required": ["id"] -} - -VPCS_START_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to start a VPCS instance", - "type": "object", - "properties": { - "id": { - "description": "VPCS device instance ID", - "type": "integer" - }, - }, - "additionalProperties": False, - "required": ["id"] -} - -VPCS_STOP_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to stop a VPCS instance", - "type": "object", - "properties": { - "id": { - "description": "VPCS device instance ID", - "type": "integer" - }, - }, - "additionalProperties": False, - "required": ["id"] -} - -VPCS_RELOAD_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to reload a VPCS instance", - "type": "object", - "properties": { - "id": { - "description": "VPCS device instance ID", - "type": "integer" - }, - }, - "additionalProperties": False, - "required": ["id"] -} - -VPCS_ALLOCATE_UDP_PORT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to allocate an UDP port for a VPCS instance", - "type": "object", - "properties": { - "id": { - "description": "VPCS device instance ID", - "type": "integer" - }, - "port_id": { - "description": "Unique port identifier for the VPCS instance", - "type": "integer" - }, - }, - "additionalProperties": False, - "required": ["id", "port_id"] -} - -VPCS_ADD_NIO_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to add a NIO for a VPCS 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": "VPCS device instance ID", - "type": "integer" - }, - "port_id": { - "description": "Unique port identifier for the VPCS instance", - "type": "integer" - }, - "port": { - "description": "Port number", - "type": "integer", - "minimum": 0, - "maximum": 0 - }, - "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"] -} - -VPCS_DELETE_NIO_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to delete a NIO for a VPCS instance", - "type": "object", - "properties": { - "id": { - "description": "VPCS device instance ID", - "type": "integer" - }, - "port": { - "description": "Port number", - "type": "integer", - "minimum": 0, - "maximum": 0 - }, - }, - "additionalProperties": False, - "required": ["id", "port"] -} - -VPCS_EXPORT_CONFIG_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to export the script file of a VPCS instance", - "type": "object", - "properties": { - "id": { - "description": "VPCS device instance ID", - "type": "integer" - }, - }, - "additionalProperties": False, - "required": ["id"] -} diff --git a/gns3server/modules/old_vpcs/vpcs_device.py b/gns3server/modules/old_vpcs/vpcs_device.py deleted file mode 100644 index 65664f39..00000000 --- a/gns3server/modules/old_vpcs/vpcs_device.py +++ /dev/null @@ -1,557 +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 . - -""" -VPCS device management (creates command line, processes, files etc.) in -order to run an VPCS instance. -""" - -import os -import sys -import subprocess -import signal -import shutil -import re - -from pkg_resources import parse_version -from .vpcs_error import VPCSError -from .adapters.ethernet_adapter import EthernetAdapter -from .nios.nio_udp import NIO_UDP -from .nios.nio_tap import NIO_TAP -from ..attic import find_unused_port - -import logging -log = logging.getLogger(__name__) - - -class VPCSDevice(object): - """ - VPCS device implementation. - - :param name: name of this VPCS device - :param path: path to VPCS executable - :param working_dir: path to a working directory - :param vpcs_id: VPCS instance ID - :param console: TCP console port - :param console_host: IP address to bind for console connections - :param console_start_port_range: TCP console port range start - :param console_end_port_range: TCP console port range end - """ - - _instances = [] - _allocated_console_ports = [] - - def __init__(self, - name, - path, - working_dir, - vpcs_id=None, - console=None, - console_host="0.0.0.0", - console_start_port_range=4512, - console_end_port_range=5000): - - - if not vpcs_id: - # find an instance identifier is none is provided (1 <= id <= 255) - # This 255 limit is due to a restriction on the number of possible - # MAC addresses given in VPCS using the -m option - self._id = 0 - for identifier in range(1, 256): - if identifier not in self._instances: - self._id = identifier - self._instances.append(self._id) - break - - if self._id == 0: - raise VPCSError("Maximum number of VPCS instances reached") - else: - if vpcs_id in self._instances: - raise VPCSError("VPCS identifier {} is already used by another VPCS device".format(vpcs_id)) - self._id = vpcs_id - self._instances.append(self._id) - - self._name = name - self._path = path - self._console = console - self._working_dir = None - self._console_host = console_host - self._command = [] - self._process = None - self._vpcs_stdout_file = "" - self._started = False - self._console_start_port_range = console_start_port_range - self._console_end_port_range = console_end_port_range - - # VPCS settings - self._script_file = "" - self._ethernet_adapter = EthernetAdapter() # one adapter with 1 Ethernet interface - - working_dir_path = os.path.join(working_dir, "vpcs", "pc-{}".format(self._id)) - - if vpcs_id and not os.path.isdir(working_dir_path): - raise VPCSError("Working directory {} doesn't exist".format(working_dir_path)) - - # create the device own working directory - self.working_dir = working_dir_path - - if not self._console: - # allocate a console port - try: - self._console = find_unused_port(self._console_start_port_range, - self._console_end_port_range, - self._console_host, - ignore_ports=self._allocated_console_ports) - except Exception as e: - raise VPCSError(e) - - if self._console in self._allocated_console_ports: - raise VPCSError("Console port {} is already used by another VPCS device".format(console)) - self._allocated_console_ports.append(self._console) - - log.info("VPCS device {name} [id={id}] has been created".format(name=self._name, - id=self._id)) - - def defaults(self): - """ - Returns all the default attribute values for VPCS. - - :returns: default values (dictionary) - """ - - vpcs_defaults = {"name": self._name, - "script_file": self._script_file, - "console": self._console} - - return vpcs_defaults - - @property - def id(self): - """ - Returns the unique ID for this VPCS device. - - :returns: id (integer) - """ - - return self._id - - @classmethod - def reset(cls): - """ - Resets allocated instance list. - """ - - cls._instances.clear() - cls._allocated_console_ports.clear() - - @property - def name(self): - """ - Returns the name of this VPCS device. - - :returns: name - """ - - return self._name - - @name.setter - def name(self, new_name): - """ - Sets the name of this VPCS device. - - :param new_name: name - """ - - if self._script_file: - # update the startup.vpc - config_path = os.path.join(self._working_dir, "startup.vpc") - if os.path.isfile(config_path): - try: - with open(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 VPCSError("Could not amend the configuration {}: {}".format(config_path, e)) - - log.info("VPCS {name} [id={id}]: renamed to {new_name}".format(name=self._name, - id=self._id, - new_name=new_name)) - self._name = new_name - - @property - def path(self): - """ - Returns the path to the VPCS executable. - - :returns: path to VPCS - """ - - return self._path - - @path.setter - def path(self, path): - """ - Sets the path to the VPCS executable. - - :param path: path to VPCS - """ - - self._path = path - log.info("VPCS {name} [id={id}]: path changed to {path}".format(name=self._name, - id=self._id, - path=path)) - - @property - def working_dir(self): - """ - Returns current working directory - - :returns: path to the working directory - """ - - return self._working_dir - - @working_dir.setter - def working_dir(self, working_dir): - """ - Sets the working directory for VPCS. - - :param working_dir: path to the working directory - """ - - try: - os.makedirs(working_dir) - except FileExistsError: - pass - except OSError as e: - raise VPCSError("Could not create working directory {}: {}".format(working_dir, e)) - - self._working_dir = working_dir - log.info("VPCS {name} [id={id}]: working directory changed to {wd}".format(name=self._name, - id=self._id, - wd=self._working_dir)) - - @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 in self._allocated_console_ports: - raise VPCSError("Console port {} is already used by another VPCS device".format(console)) - - self._allocated_console_ports.remove(self._console) - self._console = console - self._allocated_console_ports.append(self._console) - log.info("VPCS {name} [id={id}]: console port set to {port}".format(name=self._name, - id=self._id, - port=console)) - - def command(self): - """ - Returns the VPCS command line. - - :returns: VPCS command line (string) - """ - - return " ".join(self._build_command()) - - def delete(self): - """ - Deletes this VPCS device. - """ - - self.stop() - if self._id in self._instances: - self._instances.remove(self._id) - - if self.console and self.console in self._allocated_console_ports: - self._allocated_console_ports.remove(self.console) - - log.info("VPCS device {name} [id={id}] has been deleted".format(name=self._name, - id=self._id)) - - def clean_delete(self): - """ - Deletes this VPCS device & all files (configs, logs etc.) - """ - - self.stop() - if self._id in self._instances: - self._instances.remove(self._id) - - if self.console: - self._allocated_console_ports.remove(self.console) - - try: - shutil.rmtree(self._working_dir) - except OSError as e: - log.error("could not delete VPCS device {name} [id={id}]: {error}".format(name=self._name, - id=self._id, - error=e)) - return - - log.info("VPCS device {name} [id={id}] has been deleted (including associated files)".format(name=self._name, - id=self._id)) - - @property - def started(self): - """ - Returns either this VPCS device has been started or not. - - :returns: boolean - """ - - return self._started - - def _check_vpcs_version(self): - """ - Checks if the VPCS executable version is >= 0.5b1. - """ - - try: - output = subprocess.check_output([self._path, "-v"], cwd=self._working_dir) - match = re.search("Welcome to Virtual PC Simulator, version ([0-9a-z\.]+)", output.decode("utf-8")) - if match: - version = match.group(1) - if parse_version(version) < parse_version("0.5b1"): - raise VPCSError("VPCS executable version must be >= 0.5b1") - else: - raise VPCSError("Could not determine the VPCS version for {}".format(self._path)) - except (OSError, subprocess.SubprocessError) as e: - raise VPCSError("Error while looking for the VPCS version: {}".format(e)) - - def start(self): - """ - Starts the VPCS process. - """ - - if not self.is_running(): - - if not self._path: - raise VPCSError("No path to a VPCS executable has been set") - - if not os.path.isfile(self._path): - raise VPCSError("VPCS program '{}' is not accessible".format(self._path)) - - if not os.access(self._path, os.X_OK): - raise VPCSError("VPCS program '{}' is not executable".format(self._path)) - - self._check_vpcs_version() - - if not self._ethernet_adapter.get_nio(0): - raise VPCSError("This VPCS instance must be connected in order to start") - - self._command = self._build_command() - try: - log.info("starting VPCS: {}".format(self._command)) - self._vpcs_stdout_file = os.path.join(self._working_dir, "vpcs.log") - log.info("logging to {}".format(self._vpcs_stdout_file)) - flags = 0 - if sys.platform.startswith("win32"): - flags = subprocess.CREATE_NEW_PROCESS_GROUP - with open(self._vpcs_stdout_file, "w") as fd: - self._process = subprocess.Popen(self._command, - stdout=fd, - stderr=subprocess.STDOUT, - cwd=self._working_dir, - creationflags=flags) - log.info("VPCS instance {} started PID={}".format(self._id, self._process.pid)) - self._started = True - except (OSError, subprocess.SubprocessError) as e: - vpcs_stdout = self.read_vpcs_stdout() - log.error("could not start VPCS {}: {}\n{}".format(self._path, e, vpcs_stdout)) - raise VPCSError("could not start VPCS {}: {}\n{}".format(self._path, e, vpcs_stdout)) - - def stop(self): - """ - Stops the VPCS process. - """ - - # stop the VPCS process - if self.is_running(): - log.info("stopping VPCS instance {} PID={}".format(self._id, self._process.pid)) - if sys.platform.startswith("win32"): - self._process.send_signal(signal.CTRL_BREAK_EVENT) - else: - self._process.terminate() - - self._process.wait() - - self._process = None - self._started = False - - def read_vpcs_stdout(self): - """ - Reads the standard output of the VPCS process. - Only use when the process has been stopped or has crashed. - """ - - output = "" - if self._vpcs_stdout_file: - try: - with open(self._vpcs_stdout_file, errors="replace") as file: - output = file.read() - except OSError as e: - log.warn("could not read {}: {}".format(self._vpcs_stdout_file, e)) - return output - - def is_running(self): - """ - Checks if the VPCS process is running - - :returns: True or False - """ - - if self._process and self._process.poll() is None: - return True - return False - - def port_add_nio_binding(self, port_id, nio): - """ - Adds a port NIO binding. - - :param port_id: port ID - :param nio: NIO instance to add to the slot/port - """ - - if not self._ethernet_adapter.port_exists(port_id): - raise VPCSError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=self._ethernet_adapter, - port_id=port_id)) - - self._ethernet_adapter.add_nio(port_id, nio) - log.info("VPCS {name} [id={id}]: {nio} added to port {port_id}".format(name=self._name, - id=self._id, - nio=nio, - port_id=port_id)) - - def port_remove_nio_binding(self, port_id): - """ - Removes a port NIO binding. - - :param port_id: port ID - - :returns: NIO instance - """ - - if not self._ethernet_adapter.port_exists(port_id): - raise VPCSError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=self._ethernet_adapter, - port_id=port_id)) - - nio = self._ethernet_adapter.get_nio(port_id) - self._ethernet_adapter.remove_nio(port_id) - log.info("VPCS {name} [id={id}]: {nio} removed from port {port_id}".format(name=self._name, - id=self._id, - nio=nio, - port_id=port_id)) - return nio - - def _build_command(self): - """ - Command to start the VPCS process. - (to be passed to subprocess.Popen()) - - VPCS command line: - usage: vpcs [options] [scriptfile] - Option: - -h print this help then exit - -v print version information then exit - - -i num number of vpc instances to start (default is 9) - -p port run as a daemon listening on the tcp 'port' - -m num start byte of ether address, default from 0 - -r file load and execute script file - compatible with older versions, DEPRECATED. - - -e tap mode, using /dev/tapx by default (linux only) - -u udp mode, default - - udp mode options: - -s port local udp base port, default from 20000 - -c port remote udp base port (dynamips udp port), default from 30000 - -t ip remote host IP, default 127.0.0.1 - - tap mode options: - -d device device name, works only when -i is set to 1 - - hypervisor mode option: - -H port run as the hypervisor listening on the tcp 'port' - - If no 'scriptfile' specified, vpcs will read and execute the file named - 'startup.vpc' if it exsits in the current directory. - - """ - - command = [self._path] - command.extend(["-p", str(self._console)]) # listen to console port - - nio = self._ethernet_adapter.get_nio(0) - if nio: - if isinstance(nio, NIO_UDP): - # UDP tunnel - command.extend(["-s", str(nio.lport)]) # source UDP port - command.extend(["-c", str(nio.rport)]) # destination UDP port - command.extend(["-t", nio.rhost]) # destination host - - elif isinstance(nio, NIO_TAP): - # TAP interface - command.extend(["-e"]) - command.extend(["-d", nio.tap_device]) - - command.extend(["-m", str(self._id)]) # the unique ID is used to set the MAC address offset - command.extend(["-i", "1"]) # option to start only one VPC instance - command.extend(["-F"]) # option to avoid the daemonization of VPCS - if self._script_file: - command.extend([self._script_file]) - return command - - @property - def script_file(self): - """ - Returns the script-file for this VPCS instance. - - :returns: path to script-file - """ - - return self._script_file - - @script_file.setter - def script_file(self, script_file): - """ - Sets the script-file for this VPCS instance. - - :param script_file: path to base-script-file - """ - - self._script_file = script_file - log.info("VPCS {name} [id={id}]: script_file set to {config}".format(name=self._name, - id=self._id, - config=self._script_file)) diff --git a/gns3server/modules/old_vpcs/vpcs_error.py b/gns3server/modules/old_vpcs/vpcs_error.py deleted file mode 100644 index 167129ba..00000000 --- a/gns3server/modules/old_vpcs/vpcs_error.py +++ /dev/null @@ -1,39 +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 . - -""" -Custom exceptions for VPCS module. -""" - - -class VPCSError(Exception): - - def __init__(self, message, original_exception=None): - - Exception.__init__(self, message) - if isinstance(message, Exception): - message = str(message) - self._message = message - self._original_exception = original_exception - - def __repr__(self): - - return self._message - - def __str__(self): - - return self._message diff --git a/gns3server/modules/vpcs/__init__.py b/gns3server/modules/vpcs/__init__.py index 52191f2f..6ad5d8cc 100644 --- a/gns3server/modules/vpcs/__init__.py +++ b/gns3server/modules/vpcs/__init__.py @@ -20,8 +20,8 @@ VPCS server module. """ from ..base_manager import BaseManager -from .vpcs_device import VPCSDevice +from .vpcs_vm import VPCSVM class VPCS(BaseManager): - _VM_CLASS = VPCSDevice + _VM_CLASS = VPCSVM diff --git a/gns3server/modules/vpcs/vpcs_device.py b/gns3server/modules/vpcs/vpcs_vm.py similarity index 96% rename from gns3server/modules/vpcs/vpcs_device.py rename to gns3server/modules/vpcs/vpcs_vm.py index 44b09682..a1ffdd57 100644 --- a/gns3server/modules/vpcs/vpcs_device.py +++ b/gns3server/modules/vpcs/vpcs_vm.py @@ -16,7 +16,7 @@ # along with this program. If not, see . """ -VPCS device management (creates command line, processes, files etc.) in +VPCS vm management (creates command line, processes, files etc.) in order to run an VPCS instance. """ @@ -42,11 +42,11 @@ import logging log = logging.getLogger(__name__) -class VPCSDevice(BaseVM): +class VPCSVM(BaseVM): """ - VPCS device implementation. + VPCS vm implementation. - :param name: name of this VPCS device + :param name: name of this VPCS vm :param uuid: VPCS instance UUID :param project: Project instance :param manager: parent VM Manager @@ -78,7 +78,7 @@ class VPCSDevice(BaseVM): # if vpcs_id and not os.path.isdir(working_dir_path): # raise VPCSError("Working directory {} doesn't exist".format(working_dir_path)) # - # # create the device own working directory + # # create the vm own working directory # self.working_dir = working_dir_path # try: @@ -113,7 +113,7 @@ class VPCSDevice(BaseVM): @property def console(self): """ - Returns the console port of this VPCS device. + Returns the console port of this VPCS vm. :returns: console port """ @@ -124,7 +124,7 @@ class VPCSDevice(BaseVM): @BaseVM.name.setter def name(self, new_name): """ - Sets the name of this VPCS device. + Sets the name of this VPCS vm. :param new_name: name """ @@ -265,10 +265,10 @@ class VPCSDevice(BaseVM): raise VPCSError("Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e)) nio = NIO_UDP(lport, rhost, rport) elif nio_settings["type"] == "nio_tap": - tap_device = nio_settings["tap_device"] + tap_vm = nio_settings["tap_device"] if not has_privileged_access(self._path): - raise VPCSError("{} has no privileged access to {}.".format(self._path, tap_device)) - nio = NIO_TAP(tap_device) + raise VPCSError("{} has no privileged access to {}.".format(self._path, tap_vm)) + nio = NIO_TAP(tap_vm) if not nio: raise VPCSError("Requested NIO does not exist or is not supported: {}".format(nio_settings["type"])) @@ -326,7 +326,7 @@ class VPCSDevice(BaseVM): -t ip remote host IP, default 127.0.0.1 tap mode options: - -d device device name, works only when -i is set to 1 + -d vm device name, works only when -i is set to 1 hypervisor mode option: -H port run as the hypervisor listening on the tcp 'port' @@ -352,7 +352,7 @@ class VPCSDevice(BaseVM): elif isinstance(nio, NIO_TAP): # TAP interface command.extend(["-e"]) - command.extend(["-d", nio.tap_device]) + command.extend(["-d", nio.tap_vm]) # FIXME: find workaround # command.extend(["-m", str(self._id)]) # the unique ID is used to set the MAC address offset diff --git a/tests/api/test_vpcs.py b/tests/api/test_vpcs.py index 04d01c63..205e74a0 100644 --- a/tests/api/test_vpcs.py +++ b/tests/api/test_vpcs.py @@ -49,7 +49,7 @@ def test_vpcs_nio_create_udp(server, vm): assert response.json["type"] == "nio_udp" -@patch("gns3server.modules.vpcs.vpcs_device.has_privileged_access", return_value=True) +@patch("gns3server.modules.vpcs.vpcs_vm.has_privileged_access", return_value=True) def test_vpcs_nio_create_tap(mock, server, vm): response = server.post("/vpcs/{}/ports/0/nio".format(vm["uuid"]), {"type": "nio_tap", "tap_device": "test"}) diff --git a/tests/modules/vpcs/test_vpcs_device.py b/tests/modules/vpcs/test_vpcs_vm.py similarity index 80% rename from tests/modules/vpcs/test_vpcs_device.py rename to tests/modules/vpcs/test_vpcs_vm.py index 2fe1aa26..57cf71d8 100644 --- a/tests/modules/vpcs/test_vpcs_device.py +++ b/tests/modules/vpcs/test_vpcs_vm.py @@ -23,7 +23,7 @@ from tests.utils import asyncio_patch from tests.api.base import loop, project from asyncio.subprocess import Process from unittest.mock import patch, MagicMock -from gns3server.modules.vpcs.vpcs_device import VPCSDevice +from gns3server.modules.vpcs.vpcs_vm import VPCSVM from gns3server.modules.vpcs.vpcs_error import VPCSError from gns3server.modules.vpcs import VPCS from gns3server.modules.port_manager import PortManager @@ -38,7 +38,7 @@ def manager(): @patch("subprocess.check_output", return_value="Welcome to Virtual PC Simulator, version 0.6".encode("utf-8")) def test_vm(manager): - vm = VPCSDevice("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) assert vm.name == "test" assert vm.uuid == "00010203-0405-0607-0809-0a0b0c0d0e0f" @@ -46,7 +46,7 @@ def test_vm(manager): @patch("subprocess.check_output", return_value="Welcome to Virtual PC Simulator, version 0.1".encode("utf-8")) def test_vm_invalid_vpcs_version(project, manager): with pytest.raises(VPCSError): - vm = VPCSDevice("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) assert vm.name == "test" assert vm.uuid == "00010203-0405-0607-0809-0a0b0c0d0e0f" @@ -54,14 +54,14 @@ def test_vm_invalid_vpcs_version(project, manager): @patch("gns3server.config.Config.get_section_config", return_value={"path": "/bin/test_fake"}) def test_vm_invalid_vpcs_path(project, manager): with pytest.raises(VPCSError): - vm = VPCSDevice("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) assert vm.name == "test" assert vm.uuid == "00010203-0405-0607-0809-0a0b0c0d0e0f" def test_start(project, loop, manager): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): - vm = VPCSDevice("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) nio = vm.port_add_nio_binding(0, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) loop.run_until_complete(asyncio.async(vm.start())) @@ -71,7 +71,7 @@ def test_start(project, loop, manager): def test_stop(project, loop, manager): process = MagicMock() with asyncio_patch("asyncio.create_subprocess_exec", return_value=process): - vm = VPCSDevice("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) nio = vm.port_add_nio_binding(0, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) loop.run_until_complete(asyncio.async(vm.start())) @@ -82,28 +82,28 @@ def test_stop(project, loop, manager): def test_add_nio_binding_udp(manager): - vm = VPCSDevice("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) nio = vm.port_add_nio_binding(0, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) assert nio.lport == 4242 def test_add_nio_binding_tap(project, manager): - vm = VPCSDevice("test", 42, project, manager) - with patch("gns3server.modules.vpcs.vpcs_device.has_privileged_access", return_value=True): + vm = VPCSVM("test", 42, project, manager) + with patch("gns3server.modules.vpcs.vpcs_vm.has_privileged_access", return_value=True): nio = vm.port_add_nio_binding(0, {"type": "nio_tap", "tap_device": "test"}) assert nio.tap_device == "test" def test_add_nio_binding_tap_no_privileged_access(manager): - vm = VPCSDevice("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) - with patch("gns3server.modules.vpcs.vpcs_device.has_privileged_access", return_value=False): + vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + with patch("gns3server.modules.vpcs.vpcs_vm.has_privileged_access", return_value=False): with pytest.raises(VPCSError): vm.port_add_nio_binding(0, {"type": "nio_tap", "tap_device": "test"}) assert vm._ethernet_adapter.ports[0] is None def test_port_remove_nio_binding(manager): - vm = VPCSDevice("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) nio = vm.port_add_nio_binding(0, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) vm.port_remove_nio_binding(0) assert vm._ethernet_adapter.ports[0] is None