diff --git a/gns3server/old_modules/iou/__init__.py b/gns3server/old_modules/iou/__init__.py
deleted file mode 100644
index 04c7e4c0..00000000
--- a/gns3server/old_modules/iou/__init__.py
+++ /dev/null
@@ -1,843 +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 .
-
-"""
-IOU server module.
-"""
-
-import os
-import base64
-import ntpath
-import stat
-import tempfile
-import socket
-import shutil
-
-from gns3server.modules import IModule
-from gns3server.config import Config
-from gns3dms.cloud.rackspace_ctrl import get_provider
-from .iou_device import IOUDevice
-from .iou_error import IOUError
-from .nios.nio_udp import NIO_UDP
-from .nios.nio_tap import NIO_TAP
-from .nios.nio_generic_ethernet import NIO_GenericEthernet
-from ..attic import find_unused_port
-from ..attic import has_privileged_access
-
-from .schemas import IOU_CREATE_SCHEMA
-from .schemas import IOU_DELETE_SCHEMA
-from .schemas import IOU_UPDATE_SCHEMA
-from .schemas import IOU_START_SCHEMA
-from .schemas import IOU_STOP_SCHEMA
-from .schemas import IOU_RELOAD_SCHEMA
-from .schemas import IOU_ALLOCATE_UDP_PORT_SCHEMA
-from .schemas import IOU_ADD_NIO_SCHEMA
-from .schemas import IOU_DELETE_NIO_SCHEMA
-from .schemas import IOU_START_CAPTURE_SCHEMA
-from .schemas import IOU_STOP_CAPTURE_SCHEMA
-from .schemas import IOU_EXPORT_CONFIG_SCHEMA
-
-import logging
-log = logging.getLogger(__name__)
-
-
-class IOU(IModule):
-
- """
- IOU 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 iouyap location
- config = Config.instance()
- iou_config = config.get_section_config(name.upper())
- self._iouyap = iou_config.get("iouyap_path")
- if not self._iouyap or not os.path.isfile(self._iouyap):
- paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep)
- # look for iouyap in the current working directory and $PATH
- for path in paths:
- try:
- if "iouyap" in os.listdir(path) and os.access(os.path.join(path, "iouyap"), os.X_OK):
- self._iouyap = os.path.join(path, "iouyap")
- break
- except OSError:
- continue
-
- if not self._iouyap:
- log.warning("iouyap binary couldn't be found!")
- elif not os.access(self._iouyap, os.X_OK):
- log.warning("iouyap is not executable")
-
- # a new process start when calling IModule
- IModule.__init__(self, name, *args, **kwargs)
- self._iou_instances = {}
- self._console_start_port_range = iou_config.get("console_start_port_range", 4001)
- self._console_end_port_range = iou_config.get("console_end_port_range", 4500)
- self._allocated_udp_ports = []
- self._udp_start_port_range = iou_config.get("udp_start_port_range", 30001)
- self._udp_end_port_range = iou_config.get("udp_end_port_range", 35000)
- self._host = iou_config.get("host", kwargs["host"])
- self._console_host = iou_config.get("console_host", kwargs["console_host"])
- self._projects_dir = kwargs["projects_dir"]
- self._tempdir = kwargs["temp_dir"]
- self._working_dir = self._projects_dir
- self._server_iourc_path = iou_config.get("iourc", "")
- self._iourc = ""
-
- # check every 5 seconds
- self._iou_callback = self.add_periodic_callback(self._check_iou_is_alive, 5000)
- self._iou_callback.start()
-
- def stop(self, signum=None):
- """
- Properly stops the module.
-
- :param signum: signal number (if called by the signal handler)
- """
-
- self._iou_callback.stop()
-
- # delete all IOU instances
- for iou_id in self._iou_instances:
- iou_instance = self._iou_instances[iou_id]
- iou_instance.delete()
-
- self.delete_iourc_file()
-
- IModule.stop(self, signum) # this will stop the I/O loop
-
- def _check_iou_is_alive(self):
- """
- Periodic callback to check if IOU and iouyap are alive
- for each IOU instance.
-
- Sends a notification to the client if not.
- """
-
- for iou_id in self._iou_instances:
- iou_instance = self._iou_instances[iou_id]
- if iou_instance.started and (not iou_instance.is_running() or not iou_instance.is_iouyap_running()):
- notification = {"module": self.name,
- "id": iou_id,
- "name": iou_instance.name}
- if not iou_instance.is_running():
- stdout = iou_instance.read_iou_stdout()
- notification["message"] = "IOU has stopped running"
- notification["details"] = stdout
- self.send_notification("{}.iou_stopped".format(self.name), notification)
- elif not iou_instance.is_iouyap_running():
- stdout = iou_instance.read_iouyap_stdout()
- notification["message"] = "iouyap has stopped running"
- notification["details"] = stdout
- self.send_notification("{}.iouyap_stopped".format(self.name), notification)
- iou_instance.stop()
-
- def get_iou_instance(self, iou_id):
- """
- Returns an IOU device instance.
-
- :param iou_id: IOU device identifier
-
- :returns: IOUDevice instance
- """
-
- if iou_id not in self._iou_instances:
- log.debug("IOU device ID {} doesn't exist".format(iou_id), exc_info=1)
- self.send_custom_error("IOU device ID {} doesn't exist".format(iou_id))
- return None
- return self._iou_instances[iou_id]
-
- def delete_iourc_file(self):
- """
- Deletes the IOURC file.
- """
-
- if self._iourc and os.path.isfile(self._iourc):
- try:
- log.info("deleting iourc file {}".format(self._iourc))
- os.remove(self._iourc)
- except OSError as e:
- log.warn("could not delete iourc file {}: {}".format(self._iourc, e))
-
- @IModule.route("iou.reset")
- def reset(self, request=None):
- """
- Resets the module (JSON-RPC notification).
-
- :param request: JSON request (not used)
- """
-
- # delete all IOU instances
- for iou_id in self._iou_instances:
- iou_instance = self._iou_instances[iou_id]
- iou_instance.delete()
-
- # resets the instance IDs
- IOUDevice.reset()
-
- self._iou_instances.clear()
- self._allocated_udp_ports.clear()
- self.delete_iourc_file()
-
- self._working_dir = self._projects_dir
- log.info("IOU module has been reset")
-
- @IModule.route("iou.settings")
- def settings(self, request):
- """
- Set or update settings.
-
- Mandatory request parameters:
- - iourc (base64 encoded iourc file)
-
- Optional request parameters:
- - iouyap (path to iouyap)
- - 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 "iourc" in request:
- iourc_content = base64.decodebytes(request["iourc"].encode("utf-8")).decode("utf-8")
- iourc_content = iourc_content.replace("\r\n", "\n") # dos2unix
- try:
- with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
- log.info("saving iourc file content to {}".format(f.name))
- f.write(iourc_content)
- self._iourc = f.name
- except OSError as e:
- raise IOUError("Could not create the iourc file: {}".format(e))
-
- if "iouyap" in request and request["iouyap"]:
- self._iouyap = request["iouyap"]
- log.info("iouyap path set to {}".format(self._iouyap))
-
- 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 iou_id in self._iou_instances:
- iou_instance = self._iou_instances[iou_id]
- iou_instance.working_dir = os.path.join(self._working_dir, "iou", "device-{}".format(iou_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("iou.create")
- def iou_create(self, request):
- """
- Creates a new IOU instance.
-
- Mandatory request parameters:
- - path (path to the IOU executable)
-
- Optional request parameters:
- - name (IOU name)
- - console (IOU console port)
-
- Response parameters:
- - id (IOU instance identifier)
- - name (IOU name)
- - default settings
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, IOU_CREATE_SCHEMA):
- return
-
- name = request["name"]
- iou_path = request["path"]
- console = request.get("console")
- iou_id = request.get("iou_id")
-
- updated_iou_path = os.path.join(self.images_directory, iou_path)
- if os.path.isfile(updated_iou_path):
- iou_path = updated_iou_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(iou_path)
- src = '{}/{}'.format(cloud_path, filename)
- provider = get_provider(self._cloud_settings)
- log.debug("Downloading file from {} to {}...".format(src, updated_iou_path))
- provider.download_file(src, updated_iou_path)
- log.debug("Download of {} complete.".format(src))
- # Make file executable
- st = os.stat(updated_iou_path)
- os.chmod(updated_iou_path, st.st_mode | stat.S_IEXEC)
- iou_path = updated_iou_path
-
- try:
- iou_instance = IOUDevice(name,
- iou_path,
- self._working_dir,
- iou_id,
- console,
- self._console_host,
- self._console_start_port_range,
- self._console_end_port_range)
-
- except IOUError as e:
- self.send_custom_error(str(e))
- return
-
- response = {"name": iou_instance.name,
- "id": iou_instance.id}
-
- defaults = iou_instance.defaults()
- response.update(defaults)
- self._iou_instances[iou_instance.id] = iou_instance
- self.send_response(response)
-
- @IModule.route("iou.delete")
- def iou_delete(self, request):
- """
- Deletes an IOU instance.
-
- Mandatory request parameters:
- - id (IOU instance identifier)
-
- Response parameter:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, IOU_DELETE_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- return
-
- try:
- iou_instance.clean_delete()
- del self._iou_instances[request["id"]]
- except IOUError as e:
- self.send_custom_error(str(e))
- return
-
- self.send_response(True)
-
- @IModule.route("iou.update")
- def iou_update(self, request):
- """
- Updates an IOU instance
-
- Mandatory request parameters:
- - id (IOU instance identifier)
-
- Optional request parameters:
- - any setting to update
- - initial_config_base64 (initial-config base64 encoded)
-
- Response parameters:
- - updated settings
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, IOU_UPDATE_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- return
-
- config_path = os.path.join(iou_instance.working_dir, "initial-config.cfg")
- try:
- if "initial_config_base64" in request:
- # a new initial-config has been pushed
- config = base64.decodebytes(request["initial_config_base64"].encode("utf-8")).decode("utf-8")
- config = "!\n" + config.replace("\r", "")
- config = config.replace('%h', iou_instance.name)
- try:
- with open(config_path, "w") as f:
- log.info("saving initial-config to {}".format(config_path))
- f.write(config)
- except OSError as e:
- raise IOUError("Could not save the configuration {}: {}".format(config_path, e))
- # update the request with the new local initial-config path
- request["initial_config"] = os.path.basename(config_path)
- elif "initial_config" in request:
- if os.path.isfile(request["initial_config"]) and request["initial_config"] != config_path:
- # this is a local file set in the GUI
- try:
- with open(request["initial_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', iou_instance.name)
- f.write(config)
- request["initial_config"] = os.path.basename(config_path)
- except OSError as e:
- raise IOUError("Could not save the configuration from {} to {}: {}".format(request["initial_config"], config_path, e))
- elif not os.path.isfile(config_path):
- raise IOUError("Startup-config {} could not be found on this server".format(request["initial_config"]))
- except IOUError as e:
- self.send_custom_error(str(e))
- return
-
- # update the IOU settings
- response = {}
- for name, value in request.items():
- if hasattr(iou_instance, name) and getattr(iou_instance, name) != value:
- try:
- setattr(iou_instance, name, value)
- response[name] = value
- except IOUError as e:
- self.send_custom_error(str(e))
- return
-
- self.send_response(response)
-
- @IModule.route("iou.start")
- def vm_start(self, request):
- """
- Starts an IOU instance.
-
- Mandatory request parameters:
- - id (IOU instance identifier)
-
- Response parameters:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, IOU_START_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- return
-
- try:
- iou_instance.iouyap = self._iouyap
- if self._iourc:
- iou_instance.iourc = self._iourc
- else:
- # if there is no IOURC file pushed by the client then use the server IOURC file
- iou_instance.iourc = self._server_iourc_path
- iou_instance.start()
- except IOUError as e:
- self.send_custom_error(str(e))
- return
- self.send_response(True)
-
- @IModule.route("iou.stop")
- def vm_stop(self, request):
- """
- Stops an IOU instance.
-
- Mandatory request parameters:
- - id (IOU instance identifier)
-
- Response parameters:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, IOU_STOP_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- return
-
- try:
- iou_instance.stop()
- except IOUError as e:
- self.send_custom_error(str(e))
- return
- self.send_response(True)
-
- @IModule.route("iou.reload")
- def vm_reload(self, request):
- """
- Reloads an IOU instance.
-
- Mandatory request parameters:
- - id (IOU identifier)
-
- Response parameters:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, IOU_RELOAD_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- return
-
- try:
- if iou_instance.is_running():
- iou_instance.stop()
- iou_instance.start()
- except IOUError as e:
- self.send_custom_error(str(e))
- return
- self.send_response(True)
-
- @IModule.route("iou.allocate_udp_port")
- def allocate_udp_port(self, request):
- """
- Allocates a UDP port in order to create an UDP NIO.
-
- Mandatory request parameters:
- - id (IOU 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, IOU_ALLOCATE_UDP_PORT_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_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(iou_instance.name,
- iou_instance.id,
- port,
- self._host))
- response = {"lport": port,
- "port_id": request["port_id"]}
- self.send_response(response)
-
- @IModule.route("iou.add_nio")
- def add_nio(self, request):
- """
- Adds an NIO (Network Input/Output) for an IOU instance.
-
- Mandatory request parameters:
- - id (IOU instance 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_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, IOU_ADD_NIO_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- return
-
- slot = request["slot"]
- 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 IOUError("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 has_privileged_access(self._iouyap):
- raise IOUError("{} has no privileged access to {}.".format(self._iouyap, tap_device))
- nio = NIO_TAP(tap_device)
- elif request["nio"]["type"] == "nio_generic_ethernet":
- ethernet_device = request["nio"]["ethernet_device"]
- if not has_privileged_access(self._iouyap):
- raise IOUError("{} has no privileged access to {}.".format(self._iouyap, ethernet_device))
- nio = NIO_GenericEthernet(ethernet_device)
- if not nio:
- raise IOUError("Requested NIO does not exist or is not supported: {}".format(request["nio"]["type"]))
- except IOUError as e:
- self.send_custom_error(str(e))
- return
-
- try:
- iou_instance.slot_add_nio_binding(slot, port, nio)
- except IOUError as e:
- self.send_custom_error(str(e))
- return
-
- self.send_response({"port_id": request["port_id"]})
-
- @IModule.route("iou.delete_nio")
- def delete_nio(self, request):
- """
- Deletes an NIO (Network Input/Output).
-
- Mandatory request parameters:
- - id (IOU instance 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, IOU_DELETE_NIO_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- return
-
- slot = request["slot"]
- port = request["port"]
- try:
- nio = iou_instance.slot_remove_nio_binding(slot, port)
- if isinstance(nio, NIO_UDP) and nio.lport in self._allocated_udp_ports:
- self._allocated_udp_ports.remove(nio.lport)
- except IOUError as e:
- self.send_custom_error(str(e))
- return
-
- self.send_response(True)
-
- @IModule.route("iou.start_capture")
- def start_capture(self, request):
- """
- Starts a packet capture.
-
- Mandatory request parameters:
- - id (vm identifier)
- - slot (slot number)
- - port (port number)
- - 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, IOU_START_CAPTURE_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- 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(self._working_dir, "captures", capture_file_name)
- iou_instance.start_capture(slot, port, capture_file_path, data_link_type)
- except IOUError 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("iou.stop_capture")
- def stop_capture(self, request):
- """
- Stops a packet capture.
-
- Mandatory request parameters:
- - id (vm identifier)
- - slot (slot number)
- - port (port number)
- - port_id (port identifier)
-
- Response parameters:
- - port_id (port identifier)
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, IOU_STOP_CAPTURE_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- return
-
- slot = request["slot"]
- port = request["port"]
- try:
- iou_instance.stop_capture(slot, port)
- except IOUError as e:
- self.send_custom_error(str(e))
- return
-
- response = {"port_id": request["port_id"]}
- self.send_response(response)
-
- @IModule.route("iou.export_config")
- def export_config(self, request):
- """
- Exports the initial-config from an IOU instance.
-
- Mandatory request parameters:
- - id (vm identifier)
-
- Response parameters:
- - initial_config_base64 (initial-config base64 encoded)
- - False if no configuration can be exported
- """
-
- # validate the request
- if not self.validate_request(request, IOU_EXPORT_CONFIG_SCHEMA):
- return
-
- # get the instance
- iou_instance = self.get_iou_instance(request["id"])
- if not iou_instance:
- return
-
- if not iou_instance.initial_config:
- self.send_custom_error("unable to export the initial-config because it doesn't exist")
- return
-
- response = {}
- initial_config_path = os.path.join(iou_instance.working_dir, iou_instance.initial_config)
- try:
- with open(initial_config_path, "rb") as f:
- config = f.read()
- response["initial_config_base64"] = base64.encodebytes(config).decode("utf-8")
- except OSError as e:
- self.send_custom_error("unable to export the initial-config: {}".format(e))
- return
-
- if not response:
- self.send_response(False)
- else:
- self.send_response(response)
-
- @IModule.route("iou.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/old_modules/iou/adapters/__init__.py b/gns3server/old_modules/iou/adapters/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/gns3server/old_modules/iou/adapters/adapter.py b/gns3server/old_modules/iou/adapters/adapter.py
deleted file mode 100644
index 06645e56..00000000
--- a/gns3server/old_modules/iou/adapters/adapter.py
+++ /dev/null
@@ -1,105 +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=4):
-
- 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/old_modules/iou/adapters/ethernet_adapter.py b/gns3server/old_modules/iou/adapters/ethernet_adapter.py
deleted file mode 100644
index bf96362f..00000000
--- a/gns3server/old_modules/iou/adapters/ethernet_adapter.py
+++ /dev/null
@@ -1,32 +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):
-
- """
- IOU Ethernet adapter.
- """
-
- def __init__(self):
- Adapter.__init__(self, interfaces=4)
-
- def __str__(self):
-
- return "IOU Ethernet adapter"
diff --git a/gns3server/old_modules/iou/adapters/serial_adapter.py b/gns3server/old_modules/iou/adapters/serial_adapter.py
deleted file mode 100644
index ca7d3200..00000000
--- a/gns3server/old_modules/iou/adapters/serial_adapter.py
+++ /dev/null
@@ -1,32 +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 SerialAdapter(Adapter):
-
- """
- IOU Serial adapter.
- """
-
- def __init__(self):
- Adapter.__init__(self, interfaces=4)
-
- def __str__(self):
-
- return "IOU Serial adapter"
diff --git a/gns3server/old_modules/iou/iou_device.py b/gns3server/old_modules/iou/iou_device.py
deleted file mode 100644
index ff8ff2c3..00000000
--- a/gns3server/old_modules/iou/iou_device.py
+++ /dev/null
@@ -1,1069 +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 .
-
-"""
-IOU device management (creates command line, processes, files etc.) in
-order to run an IOU instance.
-"""
-
-import os
-import re
-import signal
-import subprocess
-import argparse
-import threading
-import configparser
-import shutil
-
-from .ioucon import start_ioucon
-from .iou_error import IOUError
-from .adapters.ethernet_adapter import EthernetAdapter
-from .adapters.serial_adapter import SerialAdapter
-from .nios.nio_udp import NIO_UDP
-from .nios.nio_tap import NIO_TAP
-from .nios.nio_generic_ethernet import NIO_GenericEthernet
-from ..attic import find_unused_port
-
-import logging
-log = logging.getLogger(__name__)
-
-
-class IOUDevice(object):
-
- """
- IOU device implementation.
-
- :param name: name of this IOU device
- :param path: path to IOU executable
- :param working_dir: path to a working directory
- :param iou_id: IOU 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,
- iou_id=None,
- console=None,
- console_host="0.0.0.0",
- console_start_port_range=4001,
- console_end_port_range=4512):
-
- if not iou_id:
- # find an instance identifier if none is provided (0 < id <= 512)
- self._id = 0
- for identifier in range(1, 513):
- if identifier not in self._instances:
- self._id = identifier
- self._instances.append(self._id)
- break
-
- if self._id == 0:
- raise IOUError("Maximum number of IOU instances reached")
- else:
- if iou_id in self._instances:
- raise IOUError("IOU identifier {} is already used by another IOU device".format(iou_id))
- self._id = iou_id
- self._instances.append(self._id)
-
- self._name = name
- self._path = path
- self._iourc = ""
- self._iouyap = ""
- self._console = console
- self._working_dir = None
- self._command = []
- self._process = None
- self._iouyap_process = None
- self._iou_stdout_file = ""
- self._iouyap_stdout_file = ""
- self._ioucon_thead = None
- self._ioucon_thread_stop_event = None
- self._started = False
- self._console_host = console_host
- self._console_start_port_range = console_start_port_range
- self._console_end_port_range = console_end_port_range
-
- # IOU settings
- self._ethernet_adapters = [EthernetAdapter(), EthernetAdapter()] # one adapter = 4 interfaces
- self._serial_adapters = [SerialAdapter(), SerialAdapter()] # one adapter = 4 interfaces
- self._slots = self._ethernet_adapters + self._serial_adapters
- self._use_default_iou_values = True # for RAM & NVRAM values
- self._nvram = 128 # Kilobytes
- self._initial_config = ""
- self._ram = 256 # Megabytes
- self._l1_keepalives = False # used to overcome the always-up Ethernet interfaces (not supported by all IOSes).
-
- working_dir_path = os.path.join(working_dir, "iou", "device-{}".format(self._id))
-
- if iou_id and not os.path.isdir(working_dir_path):
- raise IOUError("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 IOUError(e)
-
- if self._console in self._allocated_console_ports:
- raise IOUError("Console port {} is already in used another IOU device".format(console))
- self._allocated_console_ports.append(self._console)
-
- log.info("IOU device {name} [id={id}] has been created".format(name=self._name,
- id=self._id))
-
- def defaults(self):
- """
- Returns all the default attribute values for IOU.
-
- :returns: default values (dictionary)
- """
-
- iou_defaults = {"name": self._name,
- "path": self._path,
- "intial_config": self._initial_config,
- "use_default_iou_values": self._use_default_iou_values,
- "ram": self._ram,
- "nvram": self._nvram,
- "ethernet_adapters": len(self._ethernet_adapters),
- "serial_adapters": len(self._serial_adapters),
- "console": self._console,
- "l1_keepalives": self._l1_keepalives}
-
- return iou_defaults
-
- @property
- def id(self):
- """
- Returns the unique ID for this IOU 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 IOU device.
-
- :returns: name
- """
-
- return self._name
-
- @name.setter
- def name(self, new_name):
- """
- Sets the name of this IOU device.
-
- :param new_name: name
- """
-
- if self._initial_config:
- # update the initial-config
- config_path = os.path.join(self._working_dir, "initial-config.cfg")
- 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 IOUError("Could not amend the configuration {}: {}".format(config_path, e))
-
- log.info("IOU {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 IOU executable.
-
- :returns: path to IOU
- """
-
- return self._path
-
- @path.setter
- def path(self, path):
- """
- Sets the path to the IOU executable.
-
- :param path: path to IOU
- """
-
- self._path = path
- log.info("IOU {name} [id={id}]: path changed to {path}".format(name=self._name,
- id=self._id,
- path=path))
-
- @property
- def iourc(self):
- """
- Returns the path to the iourc file.
-
- :returns: path to the iourc file
- """
-
- return self._iourc
-
- @iourc.setter
- def iourc(self, iourc):
- """
- Sets the path to the iourc file.
-
- :param iourc: path to the iourc file.
- """
-
- self._iourc = iourc
- log.info("IOU {name} [id={id}]: iourc file path set to {path}".format(name=self._name,
- id=self._id,
- path=self._iourc))
-
- @property
- def iouyap(self):
- """
- Returns the path to iouyap
-
- :returns: path to iouyap
- """
-
- return self._iouyap
-
- @iouyap.setter
- def iouyap(self, iouyap):
- """
- Sets the path to iouyap.
-
- :param iouyap: path to iouyap
- """
-
- self._iouyap = iouyap
- log.info("IOU {name} [id={id}]: iouyap path set to {path}".format(name=self._name,
- id=self._id,
- path=self._iouyap))
-
- @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 IOU.
-
- :param working_dir: path to the working directory
- """
-
- try:
- os.makedirs(working_dir)
- except FileExistsError:
- pass
- except OSError as e:
- raise IOUError("Could not create working directory {}: {}".format(working_dir, e))
-
- self._working_dir = working_dir
- log.info("IOU {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 IOUError("Console port {} is already used by another IOU device".format(console))
-
- self._allocated_console_ports.remove(self._console)
- self._console = console
- self._allocated_console_ports.append(self._console)
- log.info("IOU {name} [id={id}]: console port set to {port}".format(name=self._name,
- id=self._id,
- port=console))
-
- def command(self):
- """
- Returns the IOU command line.
-
- :returns: IOU command line (string)
- """
-
- return " ".join(self._build_command())
-
- def delete(self):
- """
- Deletes this IOU 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("IOU device {name} [id={id}] has been deleted".format(name=self._name,
- id=self._id))
-
- def clean_delete(self):
- """
- Deletes this IOU device & all files (nvram, initial-config 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 IOU device {name} [id={id}]: {error}".format(name=self._name,
- id=self._id,
- error=e))
- return
-
- log.info("IOU device {name} [id={id}] has been deleted (including associated files)".format(name=self._name,
- id=self._id))
-
- @property
- def started(self):
- """
- Returns either this IOU device has been started or not.
-
- :returns: boolean
- """
-
- return self._started
-
- def _update_iouyap_config(self):
- """
- Updates the iouyap.ini file.
- """
-
- iouyap_ini = os.path.join(self._working_dir, "iouyap.ini")
-
- config = configparser.ConfigParser()
- config["default"] = {"netmap": "NETMAP",
- "base_port": "49000"}
-
- bay_id = 0
- for adapter in self._slots:
- unit_id = 0
- for unit in adapter.ports.keys():
- nio = adapter.get_nio(unit)
- if nio:
- connection = None
- if isinstance(nio, NIO_UDP):
- # UDP tunnel
- connection = {"tunnel_udp": "{lport}:{rhost}:{rport}".format(lport=nio.lport,
- rhost=nio.rhost,
- rport=nio.rport)}
- elif isinstance(nio, NIO_TAP):
- # TAP interface
- connection = {"tap_dev": "{tap_device}".format(tap_device=nio.tap_device)}
-
- elif isinstance(nio, NIO_GenericEthernet):
- # Ethernet interface
- connection = {"eth_dev": "{ethernet_device}".format(ethernet_device=nio.ethernet_device)}
-
- if connection:
- interface = "{iouyap_id}:{bay}/{unit}".format(iouyap_id=str(self._id + 512), bay=bay_id, unit=unit_id)
- config[interface] = connection
-
- if nio.capturing:
- pcap_data_link_type = nio.pcap_data_link_type.upper()
- if pcap_data_link_type == "DLT_PPP_SERIAL":
- pcap_protocol = "ppp"
- elif pcap_data_link_type == "DLT_C_HDLC":
- pcap_protocol = "hdlc"
- elif pcap_data_link_type == "DLT_FRELAY":
- pcap_protocol = "fr"
- else:
- pcap_protocol = "ethernet"
- capture_info = {"pcap_file": "{pcap_file}".format(pcap_file=nio.pcap_output_file),
- "pcap_protocol": pcap_protocol,
- "pcap_overwrite": "y"}
- config[interface].update(capture_info)
-
- unit_id += 1
- bay_id += 1
-
- try:
- with open(iouyap_ini, "w") as config_file:
- config.write(config_file)
- log.info("IOU {name} [id={id}]: iouyap.ini updated".format(name=self._name,
- id=self._id))
- except OSError as e:
- raise IOUError("Could not create {}: {}".format(iouyap_ini, e))
-
- def _create_netmap_config(self):
- """
- Creates the NETMAP file.
- """
-
- netmap_path = os.path.join(self._working_dir, "NETMAP")
- try:
- with open(netmap_path, "w") as f:
- for bay in range(0, 16):
- for unit in range(0, 4):
- f.write("{iouyap_id}:{bay}/{unit}{iou_id:>5d}:{bay}/{unit}\n".format(iouyap_id=str(self._id + 512),
- bay=bay,
- unit=unit,
- iou_id=self._id))
- log.info("IOU {name} [id={id}]: NETMAP file created".format(name=self._name,
- id=self._id))
- except OSError as e:
- raise IOUError("Could not create {}: {}".format(netmap_path, e))
-
- def _start_ioucon(self):
- """
- Starts ioucon thread (for console connections).
- """
-
- if not self._ioucon_thead:
- telnet_server = "{}:{}".format(self._console_host, self.console)
- log.info("starting ioucon for IOU instance {} to accept Telnet connections on {}".format(self._name, telnet_server))
- args = argparse.Namespace(appl_id=str(self._id), debug=False, escape='^^', telnet_limit=0, telnet_server=telnet_server)
- self._ioucon_thread_stop_event = threading.Event()
- self._ioucon_thead = threading.Thread(target=start_ioucon, args=(args, self._ioucon_thread_stop_event))
- self._ioucon_thead.start()
-
- def _start_iouyap(self):
- """
- Starts iouyap (handles connections to and from this IOU device).
- """
-
- try:
- self._update_iouyap_config()
- command = [self._iouyap, "-q", str(self._id + 512)] # iouyap has always IOU ID + 512
- log.info("starting iouyap: {}".format(command))
- self._iouyap_stdout_file = os.path.join(self._working_dir, "iouyap.log")
- log.info("logging to {}".format(self._iouyap_stdout_file))
- with open(self._iouyap_stdout_file, "w") as fd:
- self._iouyap_process = subprocess.Popen(command,
- stdout=fd,
- stderr=subprocess.STDOUT,
- cwd=self._working_dir)
-
- log.info("iouyap started PID={}".format(self._iouyap_process.pid))
- except (OSError, subprocess.SubprocessError) as e:
- iouyap_stdout = self.read_iouyap_stdout()
- log.error("could not start iouyap: {}\n{}".format(e, iouyap_stdout))
- raise IOUError("Could not start iouyap: {}\n{}".format(e, iouyap_stdout))
-
- def _library_check(self):
- """
- Checks for missing shared library dependencies in the IOU image.
- """
-
- try:
- output = subprocess.check_output(["ldd", self._path])
- except (FileNotFoundError, subprocess.SubprocessError) as e:
- log.warn("could not determine the shared library dependencies for {}: {}".format(self._path, e))
- return
-
- p = re.compile("([\.\w]+)\s=>\s+not found")
- missing_libs = p.findall(output.decode("utf-8"))
- if missing_libs:
- raise IOUError("The following shared library dependencies cannot be found for IOU image {}: {}".format(self._path,
- ", ".join(missing_libs)))
-
- def start(self):
- """
- Starts the IOU process.
- """
-
- if not self.is_running():
-
- if not os.path.isfile(self._path) or not os.path.exists(self._path):
- if os.path.islink(self._path):
- raise IOUError("IOU image '{}' linked to '{}' is not accessible".format(self._path, os.path.realpath(self._path)))
- else:
- raise IOUError("IOU image '{}' is not accessible".format(self._path))
-
- try:
- with open(self._path, "rb") as f:
- # read the first 7 bytes of the file.
- elf_header_start = f.read(7)
- except OSError as e:
- raise IOUError("Cannot read ELF header for IOU image '{}': {}".format(self._path, e))
-
- # IOU images must start with the ELF magic number, be 32-bit, little endian
- # and have an ELF version of 1 normal IOS image are big endian!
- if elf_header_start != b'\x7fELF\x01\x01\x01':
- raise IOUError("'{}' is not a valid IOU image".format(self._path))
-
- if not os.access(self._path, os.X_OK):
- raise IOUError("IOU image '{}' is not executable".format(self._path))
-
- self._library_check()
-
- if not self._iourc or not os.path.isfile(self._iourc):
- raise IOUError("A valid iourc file is necessary to start IOU")
-
- if not self._iouyap or not os.path.isfile(self._iouyap):
- raise IOUError("iouyap is necessary to start IOU")
-
- self._create_netmap_config()
- # created a environment variable pointing to the iourc file.
- env = os.environ.copy()
- env["IOURC"] = self._iourc
- self._command = self._build_command()
- try:
- log.info("starting IOU: {}".format(self._command))
- self._iou_stdout_file = os.path.join(self._working_dir, "iou.log")
- log.info("logging to {}".format(self._iou_stdout_file))
- with open(self._iou_stdout_file, "w") as fd:
- self._process = subprocess.Popen(self._command,
- stdout=fd,
- stderr=subprocess.STDOUT,
- cwd=self._working_dir,
- env=env)
- log.info("IOU instance {} started PID={}".format(self._id, self._process.pid))
- self._started = True
- except FileNotFoundError as e:
- raise IOUError("could not start IOU: {}: 32-bit binary support is probably not installed".format(e))
- except (OSError, subprocess.SubprocessError) as e:
- iou_stdout = self.read_iou_stdout()
- log.error("could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout))
- raise IOUError("could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout))
-
- # start console support
- self._start_ioucon()
- # connections support
- self._start_iouyap()
-
- def stop(self):
- """
- Stops the IOU process.
- """
-
- # stop console support
- if self._ioucon_thead:
- self._ioucon_thread_stop_event.set()
- if self._ioucon_thead.is_alive():
- self._ioucon_thead.join(timeout=3.0) # wait for the thread to free the console port
- self._ioucon_thead = None
-
- # stop iouyap
- if self.is_iouyap_running():
- log.info("stopping iouyap PID={} for IOU instance {}".format(self._iouyap_process.pid, self._id))
- try:
- self._iouyap_process.terminate()
- self._iouyap_process.wait(1)
- except subprocess.TimeoutExpired:
- self._iouyap_process.kill()
- if self._iouyap_process.poll() is None:
- log.warn("iouyap PID={} for IOU instance {} is still running".format(self._iouyap_process.pid,
- self._id))
- self._iouyap_process = None
-
- # stop the IOU process
- if self.is_running():
- log.info("stopping IOU instance {} PID={}".format(self._id, self._process.pid))
- try:
- self._process.terminate()
- self._process.wait(1)
- except subprocess.TimeoutExpired:
- self._process.kill()
- if self._process.poll() is None:
- log.warn("IOU instance {} PID={} is still running".format(self._id,
- self._process.pid))
- self._process = None
- self._started = False
-
- def read_iou_stdout(self):
- """
- Reads the standard output of the IOU process.
- Only use when the process has been stopped or has crashed.
- """
-
- output = ""
- if self._iou_stdout_file:
- try:
- with open(self._iou_stdout_file, errors="replace") as file:
- output = file.read()
- except OSError as e:
- log.warn("could not read {}: {}".format(self._iou_stdout_file, e))
- return output
-
- def read_iouyap_stdout(self):
- """
- Reads the standard output of the iouyap process.
- Only use when the process has been stopped or has crashed.
- """
-
- output = ""
- if self._iouyap_stdout_file:
- try:
- with open(self._iouyap_stdout_file, errors="replace") as file:
- output = file.read()
- except OSError as e:
- log.warn("could not read {}: {}".format(self._iouyap_stdout_file, e))
- return output
-
- def is_running(self):
- """
- Checks if the IOU process is running
-
- :returns: True or False
- """
-
- if self._process and self._process.poll() is None:
- return True
- return False
-
- def is_iouyap_running(self):
- """
- Checks if the iouyap process is running
-
- :returns: True or False
- """
-
- if self._iouyap_process and self._iouyap_process.poll() is None:
- return True
- return False
-
- 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 IOUError("Slot {slot_id} doesn't exist on IOU {name}".format(name=self._name,
- slot_id=slot_id))
-
- if not adapter.port_exists(port_id):
- raise IOUError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
- port_id=port_id))
-
- adapter.add_nio(port_id, nio)
- log.info("IOU {name} [id={id}]: {nio} added to {slot_id}/{port_id}".format(name=self._name,
- id=self._id,
- nio=nio,
- slot_id=slot_id,
- port_id=port_id))
- if self.is_iouyap_running():
- self._update_iouyap_config()
- os.kill(self._iouyap_process.pid, signal.SIGHUP)
-
- 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: NIO instance
- """
-
- try:
- adapter = self._slots[slot_id]
- except IndexError:
- raise IOUError("Slot {slot_id} doesn't exist on IOU {name}".format(name=self._name,
- slot_id=slot_id))
-
- if not adapter.port_exists(port_id):
- raise IOUError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
- port_id=port_id))
-
- nio = adapter.get_nio(port_id)
- adapter.remove_nio(port_id)
- log.info("IOU {name} [id={id}]: {nio} removed from {slot_id}/{port_id}".format(name=self._name,
- id=self._id,
- nio=nio,
- slot_id=slot_id,
- port_id=port_id))
- if self.is_iouyap_running():
- self._update_iouyap_config()
- os.kill(self._iouyap_process.pid, signal.SIGHUP)
-
- return nio
-
- def _enable_l1_keepalives(self, command):
- """
- Enables L1 keepalive messages if supported.
-
- :param command: command line
- """
-
- env = os.environ.copy()
- env["IOURC"] = self._iourc
- try:
- output = subprocess.check_output([self._path, "-h"], stderr=subprocess.STDOUT, cwd=self._working_dir, env=env)
- if re.search("-l\s+Enable Layer 1 keepalive messages", output.decode("utf-8")):
- command.extend(["-l"])
- else:
- raise IOUError("layer 1 keepalive messages are not supported by {}".format(os.path.basename(self._path)))
- except (OSError, subprocess.SubprocessError) as e:
- log.warn("could not determine if layer 1 keepalive messages are supported by {}: {}".format(os.path.basename(self._path), e))
-
- def _build_command(self):
- """
- Command to start the IOU process.
- (to be passed to subprocess.Popen())
-
- IOU command line:
- Usage: [options]
- : unix-js-m | unix-is-m | unix-i-m | ...
- : instance identifier (0 < id <= 1024)
- Options:
- -e Number of Ethernet interfaces (default 2)
- -s Number of Serial interfaces (default 2)
- -n Size of nvram in Kb (default 64KB)
- -b IOS debug string
- -c Configuration file name
- -d Generate debug information
- -t Netio message trace
- -q Suppress informational messages
- -h Display this help
- -C Turn off use of host clock
- -m Megabytes of router memory (default 256MB)
- -L Disable local console, use remote console
- -l Enable Layer 1 keepalive messages
- -u UDP port base for distributed networks
- -R Ignore options from the IOURC file
- -U Disable unix: file system location
- -W Disable watchdog timer
- -N Ignore the NETMAP file
- """
-
- command = [self._path]
- if len(self._ethernet_adapters) != 2:
- command.extend(["-e", str(len(self._ethernet_adapters))])
- if len(self._serial_adapters) != 2:
- command.extend(["-s", str(len(self._serial_adapters))])
- if not self.use_default_iou_values:
- command.extend(["-n", str(self._nvram)])
- command.extend(["-m", str(self._ram)])
- command.extend(["-L"]) # disable local console, use remote console
- if self._initial_config:
- command.extend(["-c", self._initial_config])
- if self._l1_keepalives:
- self._enable_l1_keepalives(command)
- command.extend([str(self._id)])
- return command
-
- @property
- def use_default_iou_values(self):
- """
- Returns if this device uses the default IOU image values.
-
- :returns: boolean
- """
-
- return self._use_default_iou_values
-
- @use_default_iou_values.setter
- def use_default_iou_values(self, state):
- """
- Sets if this device uses the default IOU image values.
-
- :param state: boolean
- """
-
- self._use_default_iou_values = state
- if state:
- log.info("IOU {name} [id={id}]: uses the default IOU image values".format(name=self._name, id=self._id))
- else:
- log.info("IOU {name} [id={id}]: does not use the default IOU image values".format(name=self._name, id=self._id))
-
- @property
- def l1_keepalives(self):
- """
- Returns either layer 1 keepalive messages option is enabled or disabled.
-
- :returns: boolean
- """
-
- return self._l1_keepalives
-
- @l1_keepalives.setter
- def l1_keepalives(self, state):
- """
- Enables or disables layer 1 keepalive messages.
-
- :param state: boolean
- """
-
- self._l1_keepalives = state
- if state:
- log.info("IOU {name} [id={id}]: has activated layer 1 keepalive messages".format(name=self._name, id=self._id))
- else:
- log.info("IOU {name} [id={id}]: has deactivated layer 1 keepalive messages".format(name=self._name, id=self._id))
-
- @property
- def ram(self):
- """
- Returns the amount of RAM allocated to this IOU instance.
-
- :returns: amount of RAM in Mbytes (integer)
- """
-
- return self._ram
-
- @ram.setter
- def ram(self, ram):
- """
- Sets amount of RAM allocated to this IOU instance.
-
- :param ram: amount of RAM in Mbytes (integer)
- """
-
- if self._ram == ram:
- return
-
- log.info("IOU {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._ram = ram
-
- @property
- def nvram(self):
- """
- Returns the mount of NVRAM allocated to this IOU instance.
-
- :returns: amount of NVRAM in Kbytes (integer)
- """
-
- return self._nvram
-
- @nvram.setter
- def nvram(self, nvram):
- """
- Sets amount of NVRAM allocated to this IOU instance.
-
- :param nvram: amount of NVRAM in Kbytes (integer)
- """
-
- if self._nvram == nvram:
- return
-
- log.info("IOU {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 initial_config(self):
- """
- Returns the initial-config for this IOU instance.
-
- :returns: path to initial-config file
- """
-
- return self._initial_config
-
- @initial_config.setter
- def initial_config(self, initial_config):
- """
- Sets the initial-config for this IOU instance.
-
- :param initial_config: path to initial-config file
- """
-
- self._initial_config = initial_config
- log.info("IOU {name} [id={id}]: initial_config set to {config}".format(name=self._name,
- id=self._id,
- config=self._initial_config))
-
- @property
- def ethernet_adapters(self):
- """
- Returns the number of Ethernet adapters for this IOU instance.
-
- :returns: number of adapters
- """
-
- return len(self._ethernet_adapters)
-
- @ethernet_adapters.setter
- def ethernet_adapters(self, ethernet_adapters):
- """
- Sets the number of Ethernet adapters for this IOU instance.
-
- :param ethernet_adapters: number of adapters
- """
-
- self._ethernet_adapters.clear()
- for _ in range(0, ethernet_adapters):
- self._ethernet_adapters.append(EthernetAdapter())
-
- log.info("IOU {name} [id={id}]: number of Ethernet adapters changed to {adapters}".format(name=self._name,
- id=self._id,
- adapters=len(self._ethernet_adapters)))
-
- self._slots = self._ethernet_adapters + self._serial_adapters
-
- @property
- def serial_adapters(self):
- """
- Returns the number of Serial adapters for this IOU instance.
-
- :returns: number of adapters
- """
-
- return len(self._serial_adapters)
-
- @serial_adapters.setter
- def serial_adapters(self, serial_adapters):
- """
- Sets the number of Serial adapters for this IOU instance.
-
- :param serial_adapters: number of adapters
- """
-
- self._serial_adapters.clear()
- for _ in range(0, serial_adapters):
- self._serial_adapters.append(SerialAdapter())
-
- log.info("IOU {name} [id={id}]: number of Serial adapters changed to {adapters}".format(name=self._name,
- id=self._id,
- adapters=len(self._serial_adapters)))
-
- self._slots = self._ethernet_adapters + self._serial_adapters
-
- 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 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
- """
-
- try:
- adapter = self._slots[slot_id]
- except IndexError:
- raise IOUError("Slot {slot_id} doesn't exist on IOU {name}".format(name=self._name,
- slot_id=slot_id))
-
- if not adapter.port_exists(port_id):
- raise IOUError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
- port_id=port_id))
-
- nio = adapter.get_nio(port_id)
- if nio.capturing:
- raise IOUError("Packet capture is already activated on {slot_id}/{port_id}".format(slot_id=slot_id,
- port_id=port_id))
-
- try:
- os.makedirs(os.path.dirname(output_file))
- except FileExistsError:
- pass
- except OSError as e:
- raise IOUError("Could not create captures directory {}".format(e))
-
- nio.startPacketCapture(output_file, data_link_type)
-
- log.info("IOU {name} [id={id}]: starting packet capture on {slot_id}/{port_id}".format(name=self._name,
- id=self._id,
- slot_id=slot_id,
- port_id=port_id))
-
- if self.is_iouyap_running():
- self._update_iouyap_config()
- os.kill(self._iouyap_process.pid, signal.SIGHUP)
-
- 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 IOUError("Slot {slot_id} doesn't exist on IOU {name}".format(name=self._name,
- slot_id=slot_id))
-
- if not adapter.port_exists(port_id):
- raise IOUError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
- port_id=port_id))
-
- nio = adapter.get_nio(port_id)
- nio.stopPacketCapture()
- log.info("IOU {name} [id={id}]: stopping packet capture on {slot_id}/{port_id}".format(name=self._name,
- id=self._id,
- slot_id=slot_id,
- port_id=port_id))
- if self.is_iouyap_running():
- self._update_iouyap_config()
- os.kill(self._iouyap_process.pid, signal.SIGHUP)
diff --git a/gns3server/old_modules/iou/iou_error.py b/gns3server/old_modules/iou/iou_error.py
deleted file mode 100644
index 8aac176f..00000000
--- a/gns3server/old_modules/iou/iou_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 IOU module.
-"""
-
-
-class IOUError(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/old_modules/iou/nios/__init__.py b/gns3server/old_modules/iou/nios/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/gns3server/old_modules/iou/nios/nio.py b/gns3server/old_modules/iou/nios/nio.py
deleted file mode 100644
index 0c8e610e..00000000
--- a/gns3server/old_modules/iou/nios/nio.py
+++ /dev/null
@@ -1,80 +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 .
-
-"""
-Base interface for NIOs.
-"""
-
-
-class NIO(object):
-
- """
- Network Input/Output.
- """
-
- def __init__(self):
-
- self._capturing = False
- self._pcap_output_file = ""
- self._pcap_data_link_type = ""
-
- def startPacketCapture(self, pcap_output_file, pcap_data_link_type="DLT_EN10MB"):
- """
-
- :param pcap_output_file: PCAP destination file for the capture
- :param pcap_data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB
- """
-
- self._capturing = True
- self._pcap_output_file = pcap_output_file
- self._pcap_data_link_type = pcap_data_link_type
-
- def stopPacketCapture(self):
-
- self._capturing = False
- self._pcap_output_file = ""
- self._pcap_data_link_type = ""
-
- @property
- def capturing(self):
- """
- Returns either a capture is configured on this NIO.
-
- :returns: boolean
- """
-
- return self._capturing
-
- @property
- def pcap_output_file(self):
- """
- Returns the path to the PCAP output file.
-
- :returns: path to the PCAP output file
- """
-
- return self._pcap_output_file
-
- @property
- def pcap_data_link_type(self):
- """
- Returns the PCAP data link type
-
- :returns: PCAP data link type (DLT_* value)
- """
-
- return self._pcap_data_link_type
diff --git a/gns3server/old_modules/iou/nios/nio_generic_ethernet.py b/gns3server/old_modules/iou/nios/nio_generic_ethernet.py
deleted file mode 100644
index 709e6474..00000000
--- a/gns3server/old_modules/iou/nios/nio_generic_ethernet.py
+++ /dev/null
@@ -1,50 +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 generic Ethernet NIOs (PCAP library).
-"""
-
-from .nio import NIO
-
-
-class NIO_GenericEthernet(NIO):
-
- """
- Generic Ethernet NIO.
-
- :param ethernet_device: Ethernet device name (e.g. eth0)
- """
-
- def __init__(self, ethernet_device):
-
- NIO.__init__(self)
- self._ethernet_device = ethernet_device
-
- @property
- def ethernet_device(self):
- """
- Returns the Ethernet device used by this NIO.
-
- :returns: the Ethernet device name
- """
-
- return self._ethernet_device
-
- def __str__(self):
-
- return "NIO Ethernet"
diff --git a/gns3server/old_modules/iou/nios/nio_tap.py b/gns3server/old_modules/iou/nios/nio_tap.py
deleted file mode 100644
index f6b1663f..00000000
--- a/gns3server/old_modules/iou/nios/nio_tap.py
+++ /dev/null
@@ -1,50 +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).
-"""
-
-from .nio import NIO
-
-
-class NIO_TAP(NIO):
-
- """
- TAP NIO.
-
- :param tap_device: TAP device name (e.g. tap0)
- """
-
- def __init__(self, tap_device):
-
- NIO.__init__(self)
- 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/old_modules/iou/nios/nio_udp.py b/gns3server/old_modules/iou/nios/nio_udp.py
deleted file mode 100644
index 3b25f0c4..00000000
--- a/gns3server/old_modules/iou/nios/nio_udp.py
+++ /dev/null
@@ -1,76 +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.
-"""
-
-from .nio import NIO
-
-
-class NIO_UDP(NIO):
-
- """
- 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):
-
- NIO.__init__(self)
- 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/old_modules/iou/schemas.py b/gns3server/old_modules/iou/schemas.py
deleted file mode 100644
index f1315ec3..00000000
--- a/gns3server/old_modules/iou/schemas.py
+++ /dev/null
@@ -1,472 +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 .
-
-
-IOU_CREATE_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to create a new IOU instance",
- "type": "object",
- "properties": {
- "name": {
- "description": "IOU device name",
- "type": "string",
- "minLength": 1,
- },
- "iou_id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- "console": {
- "description": "console TCP port",
- "minimum": 1,
- "maximum": 65535,
- "type": "integer"
- },
- "path": {
- "description": "path to the IOU executable",
- "type": "string",
- "minLength": 1,
- },
- "cloud_path": {
- "description": "Path to the image in the cloud object store",
- "type": "string",
- }
- },
- "additionalProperties": False,
- "required": ["name", "path"],
-}
-
-IOU_DELETE_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to delete an IOU instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-IOU_UPDATE_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to update an IOU instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- "name": {
- "description": "IOU device name",
- "type": "string",
- "minLength": 1,
- },
- "path": {
- "description": "path to the IOU executable",
- "type": "string",
- "minLength": 1,
- },
- "initial_config": {
- "description": "path to the IOU initial configuration file",
- "type": "string",
- "minLength": 1,
- },
- "ram": {
- "description": "amount of RAM in MB",
- "type": "integer"
- },
- "nvram": {
- "description": "amount of NVRAM in KB",
- "type": "integer"
- },
- "ethernet_adapters": {
- "description": "number of Ethernet adapters",
- "type": "integer",
- "minimum": 0,
- "maximum": 16,
- },
- "serial_adapters": {
- "description": "number of serial adapters",
- "type": "integer",
- "minimum": 0,
- "maximum": 16,
- },
- "console": {
- "description": "console TCP port",
- "minimum": 1,
- "maximum": 65535,
- "type": "integer"
- },
- "use_default_iou_values": {
- "description": "use the default IOU RAM & NVRAM values",
- "type": "boolean"
- },
- "l1_keepalives": {
- "description": "enable or disable layer 1 keepalive messages",
- "type": "boolean"
- },
- "initial_config_base64": {
- "description": "initial configuration base64 encoded",
- "type": "string"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-IOU_START_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to start an IOU instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-IOU_STOP_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to stop an IOU instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-IOU_RELOAD_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to reload an IOU instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-IOU_ALLOCATE_UDP_PORT_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to allocate an UDP port for an IOU instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- "port_id": {
- "description": "Unique port identifier for the IOU instance",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id", "port_id"]
-}
-
-IOU_ADD_NIO_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to add a NIO for an IOU 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": "IOU device instance ID",
- "type": "integer"
- },
- "port_id": {
- "description": "Unique port identifier for the IOU instance",
- "type": "integer"
- },
- "slot": {
- "description": "Slot number",
- "type": "integer",
- "minimum": 0,
- "maximum": 15
- },
- "port": {
- "description": "Port number",
- "type": "integer",
- "minimum": 0,
- "maximum": 3
- },
- "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"]
-}
-
-
-IOU_DELETE_NIO_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to delete a NIO for an IOU instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- "slot": {
- "description": "Slot number",
- "type": "integer",
- "minimum": 0,
- "maximum": 15
- },
- "port": {
- "description": "Port number",
- "type": "integer",
- "minimum": 0,
- "maximum": 3
- },
- },
- "additionalProperties": False,
- "required": ["id", "slot", "port"]
-}
-
-IOU_START_CAPTURE_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to start a packet capture on an IOU instance port",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- "slot": {
- "description": "Slot number",
- "type": "integer",
- "minimum": 0,
- "maximum": 15
- },
- "port": {
- "description": "Port number",
- "type": "integer",
- "minimum": 0,
- "maximum": 3
- },
- "port_id": {
- "description": "Unique port identifier for the IOU instance",
- "type": "integer"
- },
- "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", "slot", "port", "port_id", "capture_file_name"]
-}
-
-IOU_STOP_CAPTURE_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to stop a packet capture on an IOU instance port",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- "slot": {
- "description": "Slot number",
- "type": "integer",
- "minimum": 0,
- "maximum": 15
- },
- "port": {
- "description": "Port number",
- "type": "integer",
- "minimum": 0,
- "maximum": 3
- },
- "port_id": {
- "description": "Unique port identifier for the IOU instance",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id", "slot", "port", "port_id"]
-}
-
-IOU_EXPORT_CONFIG_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to export an initial-config from an IOU instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "IOU device instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
diff --git a/gns3server/old_modules/qemu/__init__.py b/gns3server/old_modules/qemu/__init__.py
deleted file mode 100644
index 01b3c72e..00000000
--- a/gns3server/old_modules/qemu/__init__.py
+++ /dev/null
@@ -1,687 +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 .
-
-"""
-QEMU server module.
-"""
-
-import sys
-import os
-import socket
-import shutil
-import subprocess
-import re
-
-from gns3server.modules import IModule
-from gns3server.config import Config
-from .qemu_vm import QemuVM
-from .qemu_error import QemuError
-from .nios.nio_udp import NIO_UDP
-from ..attic import find_unused_port
-
-from .schemas import QEMU_CREATE_SCHEMA
-from .schemas import QEMU_DELETE_SCHEMA
-from .schemas import QEMU_UPDATE_SCHEMA
-from .schemas import QEMU_START_SCHEMA
-from .schemas import QEMU_STOP_SCHEMA
-from .schemas import QEMU_SUSPEND_SCHEMA
-from .schemas import QEMU_RELOAD_SCHEMA
-from .schemas import QEMU_ALLOCATE_UDP_PORT_SCHEMA
-from .schemas import QEMU_ADD_NIO_SCHEMA
-from .schemas import QEMU_DELETE_NIO_SCHEMA
-
-import logging
-log = logging.getLogger(__name__)
-
-
-class Qemu(IModule):
-
- """
- QEMU module.
-
- :param name: module name
- :param args: arguments for the module
- :param kwargs: named arguments for the module
- """
-
- def __init__(self, name, *args, **kwargs):
-
- # a new process start when calling IModule
- IModule.__init__(self, name, *args, **kwargs)
- self._qemu_instances = {}
-
- config = Config.instance()
- qemu_config = config.get_section_config(name.upper())
- self._console_start_port_range = qemu_config.get("console_start_port_range", 5001)
- self._console_end_port_range = qemu_config.get("console_end_port_range", 5500)
- self._monitor_start_port_range = qemu_config.get("monitor_start_port_range", 5501)
- self._monitor_end_port_range = qemu_config.get("monitor_end_port_range", 6000)
- self._allocated_udp_ports = []
- self._udp_start_port_range = qemu_config.get("udp_start_port_range", 40001)
- self._udp_end_port_range = qemu_config.get("udp_end_port_range", 45500)
- self._host = qemu_config.get("host", kwargs["host"])
- self._console_host = qemu_config.get("console_host", kwargs["console_host"])
- self._monitor_host = qemu_config.get("monitor_host", "127.0.0.1")
- 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 QEMU instances
- for qemu_id in self._qemu_instances:
- qemu_instance = self._qemu_instances[qemu_id]
- qemu_instance.delete()
-
- IModule.stop(self, signum) # this will stop the I/O loop
-
- def get_qemu_instance(self, qemu_id):
- """
- Returns a QEMU VM instance.
-
- :param qemu_id: QEMU VM identifier
-
- :returns: QemuVM instance
- """
-
- if qemu_id not in self._qemu_instances:
- log.debug("QEMU VM ID {} doesn't exist".format(qemu_id), exc_info=1)
- self.send_custom_error("QEMU VM ID {} doesn't exist".format(qemu_id))
- return None
- return self._qemu_instances[qemu_id]
-
- @IModule.route("qemu.reset")
- def reset(self, request):
- """
- Resets the module.
-
- :param request: JSON request
- """
-
- # delete all QEMU instances
- for qemu_id in self._qemu_instances:
- qemu_instance = self._qemu_instances[qemu_id]
- qemu_instance.delete()
-
- # resets the instance IDs
- QemuVM.reset()
-
- self._qemu_instances.clear()
- self._allocated_udp_ports.clear()
-
- self._working_dir = self._projects_dir
- log.info("QEMU module has been reset")
-
- @IModule.route("qemu.settings")
- def settings(self, request):
- """
- Set or update settings.
-
- Optional request parameters:
- - working_dir (path to a working directory)
- - project_name
- - console_start_port_range
- - console_end_port_range
- - monitor_start_port_range
- - monitor_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 "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 qemu_id in self._qemu_instances:
- qemu_instance = self._qemu_instances[qemu_id]
- qemu_instance.working_dir = os.path.join(self._working_dir, "qemu", "vm-{}".format(qemu_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 "monitor_start_port_range" in request and "monitor_end_port_range" in request:
- self._monitor_start_port_range = request["monitor_start_port_range"]
- self._monitor_end_port_range = request["monitor_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("qemu.create")
- def qemu_create(self, request):
- """
- Creates a new QEMU VM instance.
-
- Mandatory request parameters:
- - name (QEMU VM name)
- - qemu_path (path to the Qemu binary)
-
- Optional request parameters:
- - console (QEMU VM console port)
- - monitor (QEMU VM monitor port)
-
- Response parameters:
- - id (QEMU VM instance identifier)
- - name (QEMU VM name)
- - default settings
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_CREATE_SCHEMA):
- return
-
- name = request["name"]
- qemu_path = request["qemu_path"]
- console = request.get("console")
- monitor = request.get("monitor")
- qemu_id = request.get("qemu_id")
-
- try:
- qemu_instance = QemuVM(name,
- qemu_path,
- self._working_dir,
- self._host,
- qemu_id,
- console,
- self._console_host,
- self._console_start_port_range,
- self._console_end_port_range,
- monitor,
- self._monitor_host,
- self._monitor_start_port_range,
- self._monitor_end_port_range)
-
- except QemuError as e:
- self.send_custom_error(str(e))
- return
-
- response = {"name": qemu_instance.name,
- "id": qemu_instance.id}
-
- defaults = qemu_instance.defaults()
- response.update(defaults)
- self._qemu_instances[qemu_instance.id] = qemu_instance
- self.send_response(response)
-
- @IModule.route("qemu.delete")
- def qemu_delete(self, request):
- """
- Deletes a QEMU VM instance.
-
- Mandatory request parameters:
- - id (QEMU VM instance identifier)
-
- Response parameter:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_DELETE_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_instance:
- return
-
- try:
- qemu_instance.clean_delete()
- del self._qemu_instances[request["id"]]
- except QemuError as e:
- self.send_custom_error(str(e))
- return
-
- self.send_response(True)
-
- @IModule.route("qemu.update")
- def qemu_update(self, request):
- """
- Updates a QEMU VM instance
-
- Mandatory request parameters:
- - id (QEMU VM instance identifier)
-
- Optional request parameters:
- - any setting to update
-
- Response parameters:
- - updated settings
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_UPDATE_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_instance:
- return
-
- # update the QEMU VM settings
- response = {}
- for name, value in request.items():
- if hasattr(qemu_instance, name) and getattr(qemu_instance, name) != value:
- try:
- setattr(qemu_instance, name, value)
- response[name] = value
- except QemuError as e:
- self.send_custom_error(str(e))
- return
-
- self.send_response(response)
-
- @IModule.route("qemu.start")
- def qemu_start(self, request):
- """
- Starts a QEMU VM instance.
-
- Mandatory request parameters:
- - id (QEMU VM instance identifier)
-
- Response parameters:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_START_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_instance:
- return
-
- try:
- qemu_instance.start()
- except QemuError as e:
- self.send_custom_error(str(e))
- return
- self.send_response(True)
-
- @IModule.route("qemu.stop")
- def qemu_stop(self, request):
- """
- Stops a QEMU VM instance.
-
- Mandatory request parameters:
- - id (QEMU VM instance identifier)
-
- Response parameters:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_STOP_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_instance:
- return
-
- try:
- qemu_instance.stop()
- except QemuError as e:
- self.send_custom_error(str(e))
- return
- self.send_response(True)
-
- @IModule.route("qemu.reload")
- def qemu_reload(self, request):
- """
- Reloads a QEMU VM instance.
-
- Mandatory request parameters:
- - id (QEMU VM identifier)
-
- Response parameters:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_RELOAD_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_instance:
- return
-
- try:
- qemu_instance.reload()
- except QemuError as e:
- self.send_custom_error(str(e))
- return
- self.send_response(True)
-
- @IModule.route("qemu.stop")
- def qemu_stop(self, request):
- """
- Stops a QEMU VM instance.
-
- Mandatory request parameters:
- - id (QEMU VM instance identifier)
-
- Response parameters:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_STOP_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_instance:
- return
-
- try:
- qemu_instance.stop()
- except QemuError as e:
- self.send_custom_error(str(e))
- return
- self.send_response(True)
-
- @IModule.route("qemu.suspend")
- def qemu_suspend(self, request):
- """
- Suspends a QEMU VM instance.
-
- Mandatory request parameters:
- - id (QEMU VM instance identifier)
-
- Response parameters:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_SUSPEND_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_instance:
- return
-
- try:
- qemu_instance.suspend()
- except QemuError as e:
- self.send_custom_error(str(e))
- return
- self.send_response(True)
-
- @IModule.route("qemu.allocate_udp_port")
- def allocate_udp_port(self, request):
- """
- Allocates a UDP port in order to create an UDP NIO.
-
- Mandatory request parameters:
- - id (QEMU 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, QEMU_ALLOCATE_UDP_PORT_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_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(qemu_instance.name,
- qemu_instance.id,
- port,
- self._host))
-
- response = {"lport": port,
- "port_id": request["port_id"]}
- self.send_response(response)
-
- @IModule.route("qemu.add_nio")
- def add_nio(self, request):
- """
- Adds an NIO (Network Input/Output) for a QEMU VM instance.
-
- Mandatory request parameters:
- - id (QEMU VM 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)
-
- Response parameters:
- - port_id (unique port identifier)
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_ADD_NIO_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_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 QemuError("Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e))
- nio = NIO_UDP(lport, rhost, rport)
- if not nio:
- raise QemuError("Requested NIO does not exist or is not supported: {}".format(request["nio"]["type"]))
- except QemuError as e:
- self.send_custom_error(str(e))
- return
-
- try:
- qemu_instance.port_add_nio_binding(port, nio)
- except QemuError as e:
- self.send_custom_error(str(e))
- return
-
- self.send_response({"port_id": request["port_id"]})
-
- @IModule.route("qemu.delete_nio")
- def delete_nio(self, request):
- """
- Deletes an NIO (Network Input/Output).
-
- Mandatory request parameters:
- - id (QEMU VM instance identifier)
- - port (port identifier)
-
- Response parameters:
- - True on success
-
- :param request: JSON request
- """
-
- # validate the request
- if not self.validate_request(request, QEMU_DELETE_NIO_SCHEMA):
- return
-
- # get the instance
- qemu_instance = self.get_qemu_instance(request["id"])
- if not qemu_instance:
- return
-
- port = request["port"]
- try:
- nio = qemu_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 QemuError as e:
- self.send_custom_error(str(e))
- return
-
- self.send_response(True)
-
- def _get_qemu_version(self, qemu_path):
- """
- Gets the Qemu version.
-
- :param qemu_path: path to Qemu
- """
-
- if sys.platform.startswith("win"):
- return ""
- try:
- output = subprocess.check_output([qemu_path, "-version"])
- match = re.search("version\s+([0-9a-z\-\.]+)", output.decode("utf-8"))
- if match:
- version = match.group(1)
- return version
- else:
- raise QemuError("Could not determine the Qemu version for {}".format(qemu_path))
- except subprocess.SubprocessError as e:
- raise QemuError("Error while looking for the Qemu version: {}".format(e))
-
- @IModule.route("qemu.qemu_list")
- def qemu_list(self, request):
- """
- Gets QEMU binaries list.
-
- Response parameters:
- - List of Qemu binaries
- """
-
- qemus = []
- paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep)
- # look for Qemu binaries in the current working directory and $PATH
- if sys.platform.startswith("win"):
- # add specific Windows paths
- if hasattr(sys, "frozen"):
- # add any qemu dir in the same location as gns3server.exe to the list of paths
- exec_dir = os.path.dirname(os.path.abspath(sys.executable))
- for f in os.listdir(exec_dir):
- if f.lower().startswith("qemu"):
- paths.append(os.path.join(exec_dir, f))
-
- if "PROGRAMFILES(X86)" in os.environ and os.path.exists(os.environ["PROGRAMFILES(X86)"]):
- paths.append(os.path.join(os.environ["PROGRAMFILES(X86)"], "qemu"))
- if "PROGRAMFILES" in os.environ and os.path.exists(os.environ["PROGRAMFILES"]):
- paths.append(os.path.join(os.environ["PROGRAMFILES"], "qemu"))
- elif sys.platform.startswith("darwin"):
- # add specific locations on Mac OS X regardless of what's in $PATH
- paths.extend(["/usr/local/bin", "/opt/local/bin"])
- if hasattr(sys, "frozen"):
- paths.append(os.path.abspath(os.path.join(os.getcwd(), "../../../qemu/bin/")))
- for path in paths:
- try:
- for f in os.listdir(path):
- if (f.startswith("qemu-system") or f == "qemu" or f == "qemu.exe") and \
- os.access(os.path.join(path, f), os.X_OK) and \
- os.path.isfile(os.path.join(path, f)):
- qemu_path = os.path.join(path, f)
- version = self._get_qemu_version(qemu_path)
- qemus.append({"path": qemu_path, "version": version})
- except OSError:
- continue
-
- response = {"qemus": qemus}
- self.send_response(response)
-
- @IModule.route("qemu.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/old_modules/qemu/adapters/__init__.py b/gns3server/old_modules/qemu/adapters/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/gns3server/old_modules/qemu/adapters/adapter.py b/gns3server/old_modules/qemu/adapters/adapter.py
deleted file mode 100644
index ade660f9..00000000
--- a/gns3server/old_modules/qemu/adapters/adapter.py
+++ /dev/null
@@ -1,105 +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/old_modules/qemu/adapters/ethernet_adapter.py b/gns3server/old_modules/qemu/adapters/ethernet_adapter.py
deleted file mode 100644
index 2064bb68..00000000
--- a/gns3server/old_modules/qemu/adapters/ethernet_adapter.py
+++ /dev/null
@@ -1,32 +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):
-
- """
- QEMU Ethernet adapter.
- """
-
- def __init__(self):
- Adapter.__init__(self, interfaces=1)
-
- def __str__(self):
-
- return "QEMU Ethernet adapter"
diff --git a/gns3server/old_modules/qemu/nios/__init__.py b/gns3server/old_modules/qemu/nios/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/gns3server/old_modules/qemu/nios/nio.py b/gns3server/old_modules/qemu/nios/nio.py
deleted file mode 100644
index 3c8a6b9e..00000000
--- a/gns3server/old_modules/qemu/nios/nio.py
+++ /dev/null
@@ -1,66 +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 .
-
-"""
-Base interface for NIOs.
-"""
-
-
-class NIO(object):
-
- """
- Network Input/Output.
- """
-
- def __init__(self):
-
- self._capturing = False
- self._pcap_output_file = ""
-
- def startPacketCapture(self, pcap_output_file):
- """
-
- :param pcap_output_file: PCAP destination file for the capture
- """
-
- self._capturing = True
- self._pcap_output_file = pcap_output_file
-
- def stopPacketCapture(self):
-
- self._capturing = False
- self._pcap_output_file = ""
-
- @property
- def capturing(self):
- """
- Returns either a capture is configured on this NIO.
-
- :returns: boolean
- """
-
- return self._capturing
-
- @property
- def pcap_output_file(self):
- """
- Returns the path to the PCAP output file.
-
- :returns: path to the PCAP output file
- """
-
- return self._pcap_output_file
diff --git a/gns3server/old_modules/qemu/nios/nio_udp.py b/gns3server/old_modules/qemu/nios/nio_udp.py
deleted file mode 100644
index 3b25f0c4..00000000
--- a/gns3server/old_modules/qemu/nios/nio_udp.py
+++ /dev/null
@@ -1,76 +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.
-"""
-
-from .nio import NIO
-
-
-class NIO_UDP(NIO):
-
- """
- 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):
-
- NIO.__init__(self)
- 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/old_modules/qemu/qemu_error.py b/gns3server/old_modules/qemu/qemu_error.py
deleted file mode 100644
index 55135a34..00000000
--- a/gns3server/old_modules/qemu/qemu_error.py
+++ /dev/null
@@ -1,39 +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 .
-
-"""
-Custom exceptions for QEMU module.
-"""
-
-
-class QemuError(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/old_modules/qemu/qemu_vm.py b/gns3server/old_modules/qemu/qemu_vm.py
deleted file mode 100644
index a5ae107d..00000000
--- a/gns3server/old_modules/qemu/qemu_vm.py
+++ /dev/null
@@ -1,1244 +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 .
-
-"""
-QEMU VM instance.
-"""
-
-import sys
-import os
-import shutil
-import random
-import subprocess
-import shlex
-import ntpath
-import telnetlib
-import time
-import re
-
-from gns3server.config import Config
-from gns3dms.cloud.rackspace_ctrl import get_provider
-
-from .qemu_error import QemuError
-from .adapters.ethernet_adapter import EthernetAdapter
-from .nios.nio_udp import NIO_UDP
-from ..attic import find_unused_port
-
-import logging
-log = logging.getLogger(__name__)
-
-
-class QemuVM(object):
-
- """
- QEMU VM implementation.
-
- :param name: name of this QEMU VM
- :param qemu_path: path to the QEMU binary
- :param working_dir: path to a working directory
- :param host: host/address to bind for console and UDP connections
- :param qemu_id: QEMU VM 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
- :param monitor: TCP monitor port
- :param monitor_host: IP address to bind for monitor connections
- :param monitor_start_port_range: TCP monitor port range start
- :param monitor_end_port_range: TCP monitor port range end
- """
-
- _instances = []
- _allocated_console_ports = []
- _allocated_monitor_ports = []
-
- def __init__(self,
- name,
- qemu_path,
- working_dir,
- host="127.0.0.1",
- qemu_id=None,
- console=None,
- console_host="0.0.0.0",
- console_start_port_range=5001,
- console_end_port_range=5500,
- monitor=None,
- monitor_host="0.0.0.0",
- monitor_start_port_range=5501,
- monitor_end_port_range=6000):
-
- if not qemu_id:
- self._id = 0
- for identifier in range(1, 1024):
- if identifier not in self._instances:
- self._id = identifier
- self._instances.append(self._id)
- break
-
- if self._id == 0:
- raise QemuError("Maximum number of QEMU VM instances reached")
- else:
- if qemu_id in self._instances:
- raise QemuError("QEMU identifier {} is already used by another QEMU VM instance".format(qemu_id))
- self._id = qemu_id
- self._instances.append(self._id)
-
- self._name = name
- self._working_dir = None
- self._host = host
- self._command = []
- self._started = False
- self._process = None
- self._cpulimit_process = None
- self._stdout_file = ""
- self._console_host = console_host
- self._console_start_port_range = console_start_port_range
- self._console_end_port_range = console_end_port_range
- self._monitor_host = monitor_host
- self._monitor_start_port_range = monitor_start_port_range
- self._monitor_end_port_range = monitor_end_port_range
- self._cloud_path = None
-
- # QEMU settings
- self._qemu_path = qemu_path
- self._hda_disk_image = ""
- self._hdb_disk_image = ""
- self._options = ""
- self._ram = 256
- self._console = console
- self._monitor = monitor
- self._ethernet_adapters = []
- self._adapter_type = "e1000"
- self._initrd = ""
- self._kernel_image = ""
- self._kernel_command_line = ""
- self._legacy_networking = False
- self._cpu_throttling = 0 # means no CPU throttling
- self._process_priority = "low"
-
- working_dir_path = os.path.join(working_dir, "qemu", "vm-{}".format(self._id))
-
- if qemu_id and not os.path.isdir(working_dir_path):
- raise QemuError("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 QemuError(e)
-
- if self._console in self._allocated_console_ports:
- raise QemuError("Console port {} is already used by another QEMU VM".format(console))
- self._allocated_console_ports.append(self._console)
-
- if not self._monitor:
- # allocate a monitor port
- try:
- self._monitor = find_unused_port(self._monitor_start_port_range,
- self._monitor_end_port_range,
- self._monitor_host,
- ignore_ports=self._allocated_monitor_ports)
- except Exception as e:
- raise QemuError(e)
-
- if self._monitor in self._allocated_monitor_ports:
- raise QemuError("Monitor port {} is already used by another QEMU VM".format(monitor))
- self._allocated_monitor_ports.append(self._monitor)
-
- self.adapters = 1 # creates 1 adapter by default
- log.info("QEMU VM {name} [id={id}] has been created".format(name=self._name,
- id=self._id))
-
- def defaults(self):
- """
- Returns all the default attribute values for this QEMU VM.
-
- :returns: default values (dictionary)
- """
-
- qemu_defaults = {"name": self._name,
- "qemu_path": self._qemu_path,
- "ram": self._ram,
- "hda_disk_image": self._hda_disk_image,
- "hdb_disk_image": self._hdb_disk_image,
- "options": self._options,
- "adapters": self.adapters,
- "adapter_type": self._adapter_type,
- "console": self._console,
- "monitor": self._monitor,
- "initrd": self._initrd,
- "kernel_image": self._kernel_image,
- "kernel_command_line": self._kernel_command_line,
- "legacy_networking": self._legacy_networking,
- "cpu_throttling": self._cpu_throttling,
- "process_priority": self._process_priority
- }
-
- return qemu_defaults
-
- @property
- def id(self):
- """
- Returns the unique ID for this QEMU VM.
-
- :returns: id (integer)
- """
-
- return self._id
-
- @classmethod
- def reset(cls):
- """
- Resets allocated instance list.
- """
-
- cls._instances.clear()
- cls._allocated_console_ports.clear()
- cls._allocated_monitor_ports.clear()
-
- @property
- def name(self):
- """
- Returns the name of this QEMU VM.
-
- :returns: name
- """
-
- return self._name
-
- @name.setter
- def name(self, new_name):
- """
- Sets the name of this QEMU VM.
-
- :param new_name: name
- """
-
- log.info("QEMU VM {name} [id={id}]: renamed to {new_name}".format(name=self._name,
- id=self._id,
- new_name=new_name))
-
- self._name = new_name
-
- @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 this QEMU VM.
-
- :param working_dir: path to the working directory
- """
-
- try:
- os.makedirs(working_dir)
- except FileExistsError:
- pass
- except OSError as e:
- raise QemuError("Could not create working directory {}: {}".format(working_dir, e))
-
- self._working_dir = working_dir
- log.info("QEMU VM {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 QemuError("Console port {} is already used by another QEMU VM".format(console))
-
- self._allocated_console_ports.remove(self._console)
- self._console = console
- self._allocated_console_ports.append(self._console)
-
- log.info("QEMU VM {name} [id={id}]: console port set to {port}".format(name=self._name,
- id=self._id,
- port=console))
-
- @property
- def monitor(self):
- """
- Returns the TCP monitor port.
-
- :returns: monitor port (integer)
- """
-
- return self._monitor
-
- @monitor.setter
- def monitor(self, monitor):
- """
- Sets the TCP monitor port.
-
- :param monitor: monitor port (integer)
- """
-
- if monitor in self._allocated_monitor_ports:
- raise QemuError("Monitor port {} is already used by another QEMU VM".format(monitor))
-
- self._allocated_monitor_ports.remove(self._monitor)
- self._monitor = monitor
- self._allocated_monitor_ports.append(self._monitor)
-
- log.info("QEMU VM {name} [id={id}]: monitor port set to {port}".format(name=self._name,
- id=self._id,
- port=monitor))
-
- def delete(self):
- """
- Deletes this QEMU VM.
- """
-
- 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)
-
- if self._monitor and self._monitor in self._allocated_monitor_ports:
- self._allocated_monitor_ports.remove(self._monitor)
-
- log.info("QEMU VM {name} [id={id}] has been deleted".format(name=self._name,
- id=self._id))
-
- def clean_delete(self):
- """
- Deletes this QEMU VM & all files.
- """
-
- self.stop()
- if self._id in self._instances:
- self._instances.remove(self._id)
-
- if self._console:
- self._allocated_console_ports.remove(self._console)
-
- if self._monitor:
- self._allocated_monitor_ports.remove(self._monitor)
-
- try:
- shutil.rmtree(self._working_dir)
- except OSError as e:
- log.error("could not delete QEMU VM {name} [id={id}]: {error}".format(name=self._name,
- id=self._id,
- error=e))
- return
-
- log.info("QEMU VM {name} [id={id}] has been deleted (including associated files)".format(name=self._name,
- id=self._id))
-
- @property
- def cloud_path(self):
- """
- Returns the cloud path where images can be downloaded from.
-
- :returns: cloud path
- """
-
- return self._cloud_path
-
- @cloud_path.setter
- def cloud_path(self, cloud_path):
- """
- Sets the cloud path where images can be downloaded from.
-
- :param cloud_path:
- :return:
- """
-
- self._cloud_path = cloud_path
-
- @property
- def qemu_path(self):
- """
- Returns the QEMU binary path for this QEMU VM.
-
- :returns: QEMU path
- """
-
- return self._qemu_path
-
- @qemu_path.setter
- def qemu_path(self, qemu_path):
- """
- Sets the QEMU binary path this QEMU VM.
-
- :param qemu_path: QEMU path
- """
-
- log.info("QEMU VM {name} [id={id}] has set the QEMU path to {qemu_path}".format(name=self._name,
- id=self._id,
- qemu_path=qemu_path))
- self._qemu_path = qemu_path
-
- @property
- def hda_disk_image(self):
- """
- Returns the hda disk image path for this QEMU VM.
-
- :returns: QEMU hda disk image path
- """
-
- return self._hda_disk_image
-
- @hda_disk_image.setter
- def hda_disk_image(self, hda_disk_image):
- """
- Sets the hda disk image for this QEMU VM.
-
- :param hda_disk_image: QEMU hda disk image path
- """
-
- log.info("QEMU VM {name} [id={id}] has set the QEMU hda disk image path to {disk_image}".format(name=self._name,
- id=self._id,
- disk_image=hda_disk_image))
- self._hda_disk_image = hda_disk_image
-
- @property
- def hdb_disk_image(self):
- """
- Returns the hdb disk image path for this QEMU VM.
-
- :returns: QEMU hdb disk image path
- """
-
- return self._hdb_disk_image
-
- @hdb_disk_image.setter
- def hdb_disk_image(self, hdb_disk_image):
- """
- Sets the hdb disk image for this QEMU VM.
-
- :param hdb_disk_image: QEMU hdb disk image path
- """
-
- log.info("QEMU VM {name} [id={id}] has set the QEMU hdb disk image path to {disk_image}".format(name=self._name,
- id=self._id,
- disk_image=hdb_disk_image))
- self._hdb_disk_image = hdb_disk_image
-
- @property
- def adapters(self):
- """
- Returns the number of Ethernet adapters for this QEMU VM instance.
-
- :returns: number of adapters
- """
-
- return len(self._ethernet_adapters)
-
- @adapters.setter
- def adapters(self, adapters):
- """
- Sets the number of Ethernet adapters for this QEMU VM instance.
-
- :param adapters: number of adapters
- """
-
- self._ethernet_adapters.clear()
- for adapter_id in range(0, adapters):
- self._ethernet_adapters.append(EthernetAdapter())
-
- log.info("QEMU VM {name} [id={id}]: number of Ethernet adapters changed to {adapters}".format(name=self._name,
- id=self._id,
- adapters=adapters))
-
- @property
- def adapter_type(self):
- """
- Returns the adapter type for this QEMU VM instance.
-
- :returns: adapter type (string)
- """
-
- return self._adapter_type
-
- @adapter_type.setter
- def adapter_type(self, adapter_type):
- """
- Sets the adapter type for this QEMU VM instance.
-
- :param adapter_type: adapter type (string)
- """
-
- self._adapter_type = adapter_type
-
- log.info("QEMU VM {name} [id={id}]: adapter type changed to {adapter_type}".format(name=self._name,
- id=self._id,
- adapter_type=adapter_type))
-
- @property
- def legacy_networking(self):
- """
- Returns either QEMU legacy networking commands are used.
-
- :returns: boolean
- """
-
- return self._legacy_networking
-
- @legacy_networking.setter
- def legacy_networking(self, legacy_networking):
- """
- Sets either QEMU legacy networking commands are used.
-
- :param legacy_networking: boolean
- """
-
- if legacy_networking:
- log.info("QEMU VM {name} [id={id}] has enabled legacy networking".format(name=self._name, id=self._id))
- else:
- log.info("QEMU VM {name} [id={id}] has disabled legacy networking".format(name=self._name, id=self._id))
- self._legacy_networking = legacy_networking
-
- @property
- def cpu_throttling(self):
- """
- Returns the percentage of CPU allowed.
-
- :returns: integer
- """
-
- return self._cpu_throttling
-
- @cpu_throttling.setter
- def cpu_throttling(self, cpu_throttling):
- """
- Sets the percentage of CPU allowed.
-
- :param cpu_throttling: integer
- """
-
- log.info("QEMU VM {name} [id={id}] has set the percentage of CPU allowed to {cpu}".format(name=self._name,
- id=self._id,
- cpu=cpu_throttling))
- self._cpu_throttling = cpu_throttling
- self._stop_cpulimit()
- if cpu_throttling:
- self._set_cpu_throttling()
-
- @property
- def process_priority(self):
- """
- Returns the process priority.
-
- :returns: string
- """
-
- return self._process_priority
-
- @process_priority.setter
- def process_priority(self, process_priority):
- """
- Sets the process priority.
-
- :param process_priority: string
- """
-
- log.info("QEMU VM {name} [id={id}] has set the process priority to {priority}".format(name=self._name,
- id=self._id,
- priority=process_priority))
- self._process_priority = process_priority
-
- @property
- def ram(self):
- """
- Returns the RAM amount for this QEMU VM.
-
- :returns: RAM amount in MB
- """
-
- return self._ram
-
- @ram.setter
- def ram(self, ram):
- """
- Sets the amount of RAM for this QEMU VM.
-
- :param ram: RAM amount in MB
- """
-
- log.info("QEMU VM {name} [id={id}] has set the RAM to {ram}".format(name=self._name,
- id=self._id,
- ram=ram))
- self._ram = ram
-
- @property
- def options(self):
- """
- Returns the options for this QEMU VM.
-
- :returns: QEMU options
- """
-
- return self._options
-
- @options.setter
- def options(self, options):
- """
- Sets the options for this QEMU VM.
-
- :param options: QEMU options
- """
-
- log.info("QEMU VM {name} [id={id}] has set the QEMU options to {options}".format(name=self._name,
- id=self._id,
- options=options))
- self._options = options
-
- @property
- def initrd(self):
- """
- Returns the initrd path for this QEMU VM.
-
- :returns: QEMU initrd path
- """
-
- return self._initrd
-
- @initrd.setter
- def initrd(self, initrd):
- """
- Sets the initrd path for this QEMU VM.
-
- :param initrd: QEMU initrd path
- """
-
- log.info("QEMU VM {name} [id={id}] has set the QEMU initrd path to {initrd}".format(name=self._name,
- id=self._id,
- initrd=initrd))
- self._initrd = initrd
-
- @property
- def kernel_image(self):
- """
- Returns the kernel image path for this QEMU VM.
-
- :returns: QEMU kernel image path
- """
-
- return self._kernel_image
-
- @kernel_image.setter
- def kernel_image(self, kernel_image):
- """
- Sets the kernel image path for this QEMU VM.
-
- :param kernel_image: QEMU kernel image path
- """
-
- log.info("QEMU VM {name} [id={id}] has set the QEMU kernel image path to {kernel_image}".format(name=self._name,
- id=self._id,
- kernel_image=kernel_image))
- self._kernel_image = kernel_image
-
- @property
- def kernel_command_line(self):
- """
- Returns the kernel command line for this QEMU VM.
-
- :returns: QEMU kernel command line
- """
-
- return self._kernel_command_line
-
- @kernel_command_line.setter
- def kernel_command_line(self, kernel_command_line):
- """
- Sets the kernel command line for this QEMU VM.
-
- :param kernel_command_line: QEMU kernel command line
- """
-
- log.info("QEMU VM {name} [id={id}] has set the QEMU kernel command line to {kernel_command_line}".format(name=self._name,
- id=self._id,
- kernel_command_line=kernel_command_line))
- self._kernel_command_line = kernel_command_line
-
- def _set_process_priority(self):
- """
- Changes the process priority
- """
-
- if sys.platform.startswith("win"):
- try:
- import win32api
- import win32con
- import win32process
- except ImportError:
- log.error("pywin32 must be installed to change the priority class for QEMU VM {}".format(self._name))
- else:
- log.info("setting QEMU VM {} priority class to BELOW_NORMAL".format(self._name))
- handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, 0, self._process.pid)
- if self._process_priority == "realtime":
- priority = win32process.REALTIME_PRIORITY_CLASS
- elif self._process_priority == "very high":
- priority = win32process.HIGH_PRIORITY_CLASS
- elif self._process_priority == "high":
- priority = win32process.ABOVE_NORMAL_PRIORITY_CLASS
- elif self._process_priority == "low":
- priority = win32process.BELOW_NORMAL_PRIORITY_CLASS
- elif self._process_priority == "very low":
- priority = win32process.IDLE_PRIORITY_CLASS
- else:
- priority = win32process.NORMAL_PRIORITY_CLASS
- win32process.SetPriorityClass(handle, priority)
- else:
- if self._process_priority == "realtime":
- priority = -20
- elif self._process_priority == "very high":
- priority = -15
- elif self._process_priority == "high":
- priority = -5
- elif self._process_priority == "low":
- priority = 5
- elif self._process_priority == "very low":
- priority = 19
- else:
- priority = 0
- try:
- subprocess.call(['renice', '-n', str(priority), '-p', str(self._process.pid)])
- except (OSError, subprocess.SubprocessError) as e:
- log.error("could not change process priority for QEMU VM {}: {}".format(self._name, e))
-
- def _stop_cpulimit(self):
- """
- Stops the cpulimit process.
- """
-
- if self._cpulimit_process and self._cpulimit_process.poll() is None:
- self._cpulimit_process.kill()
- try:
- self._process.wait(3)
- except subprocess.TimeoutExpired:
- log.error("could not kill cpulimit process {}".format(self._cpulimit_process.pid))
-
- def _set_cpu_throttling(self):
- """
- Limits the CPU usage for current QEMU process.
- """
-
- if not self.is_running():
- return
-
- try:
- if sys.platform.startswith("win") and hasattr(sys, "frozen"):
- cpulimit_exec = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "cpulimit", "cpulimit.exe")
- else:
- cpulimit_exec = "cpulimit"
- subprocess.Popen([cpulimit_exec, "--lazy", "--pid={}".format(self._process.pid), "--limit={}".format(self._cpu_throttling)], cwd=self._working_dir)
- log.info("CPU throttled to {}%".format(self._cpu_throttling))
- except FileNotFoundError:
- raise QemuError("cpulimit could not be found, please install it or deactivate CPU throttling")
- except (OSError, subprocess.SubprocessError) as e:
- raise QemuError("Could not throttle CPU: {}".format(e))
-
- def start(self):
- """
- Starts this QEMU VM.
- """
-
- if self.is_running():
-
- # resume the VM if it is paused
- self.resume()
- return
-
- else:
-
- if not os.path.isfile(self._qemu_path) or not os.path.exists(self._qemu_path):
- found = False
- paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep)
- # look for the qemu binary in the current working directory and $PATH
- for path in paths:
- try:
- if self._qemu_path in os.listdir(path) and os.access(os.path.join(path, self._qemu_path), os.X_OK):
- self._qemu_path = os.path.join(path, self._qemu_path)
- found = True
- break
- except OSError:
- continue
-
- if not found:
- raise QemuError("QEMU binary '{}' is not accessible".format(self._qemu_path))
-
- if self.cloud_path is not None:
- # Download from Cloud Files
- if self.hda_disk_image != "":
- _, filename = ntpath.split(self.hda_disk_image)
- src = '{}/{}'.format(self.cloud_path, filename)
- dst = os.path.join(self.working_dir, filename)
- if not os.path.isfile(dst):
- cloud_settings = Config.instance().cloud_settings()
- provider = get_provider(cloud_settings)
- log.debug("Downloading file from {} to {}...".format(src, dst))
- provider.download_file(src, dst)
- log.debug("Download of {} complete.".format(src))
- self.hda_disk_image = dst
- if self.hdb_disk_image != "":
- _, filename = ntpath.split(self.hdb_disk_image)
- src = '{}/{}'.format(self.cloud_path, filename)
- dst = os.path.join(self.working_dir, filename)
- if not os.path.isfile(dst):
- cloud_settings = Config.instance().cloud_settings()
- provider = get_provider(cloud_settings)
- log.debug("Downloading file from {} to {}...".format(src, dst))
- provider.download_file(src, dst)
- log.debug("Download of {} complete.".format(src))
- self.hdb_disk_image = dst
-
- if self.initrd != "":
- _, filename = ntpath.split(self.initrd)
- src = '{}/{}'.format(self.cloud_path, filename)
- dst = os.path.join(self.working_dir, filename)
- if not os.path.isfile(dst):
- cloud_settings = Config.instance().cloud_settings()
- provider = get_provider(cloud_settings)
- log.debug("Downloading file from {} to {}...".format(src, dst))
- provider.download_file(src, dst)
- log.debug("Download of {} complete.".format(src))
- self.initrd = dst
- if self.kernel_image != "":
- _, filename = ntpath.split(self.kernel_image)
- src = '{}/{}'.format(self.cloud_path, filename)
- dst = os.path.join(self.working_dir, filename)
- if not os.path.isfile(dst):
- cloud_settings = Config.instance().cloud_settings()
- provider = get_provider(cloud_settings)
- log.debug("Downloading file from {} to {}...".format(src, dst))
- provider.download_file(src, dst)
- log.debug("Download of {} complete.".format(src))
- self.kernel_image = dst
-
- self._command = self._build_command()
- try:
- log.info("starting QEMU: {}".format(self._command))
- self._stdout_file = os.path.join(self._working_dir, "qemu.log")
- log.info("logging to {}".format(self._stdout_file))
- with open(self._stdout_file, "w") as fd:
- self._process = subprocess.Popen(self._command,
- stdout=fd,
- stderr=subprocess.STDOUT,
- cwd=self._working_dir)
- log.info("QEMU VM instance {} started PID={}".format(self._id, self._process.pid))
- self._started = True
- except (OSError, subprocess.SubprocessError) as e:
- stdout = self.read_stdout()
- log.error("could not start QEMU {}: {}\n{}".format(self._qemu_path, e, stdout))
- raise QemuError("could not start QEMU {}: {}\n{}".format(self._qemu_path, e, stdout))
-
- self._set_process_priority()
- if self._cpu_throttling:
- self._set_cpu_throttling()
-
- def stop(self):
- """
- Stops this QEMU VM.
- """
-
- # stop the QEMU process
- if self.is_running():
- log.info("stopping QEMU VM instance {} PID={}".format(self._id, self._process.pid))
- try:
- self._process.terminate()
- self._process.wait(1)
- except subprocess.TimeoutExpired:
- self._process.kill()
- if self._process.poll() is None:
- log.warn("QEMU VM instance {} PID={} is still running".format(self._id,
- self._process.pid))
- self._process = None
- self._started = False
- self._stop_cpulimit()
-
- def _control_vm(self, command, expected=None, timeout=30):
- """
- Executes a command with QEMU monitor when this VM is running.
-
- :param command: QEMU monitor command (e.g. info status, stop etc.)
- :param timeout: how long to wait for QEMU monitor
-
- :returns: result of the command (Match object or None)
- """
-
- result = None
- if self.is_running() and self._monitor:
- log.debug("Execute QEMU monitor command: {}".format(command))
- try:
- tn = telnetlib.Telnet(self._monitor_host, self._monitor, timeout=timeout)
- except OSError as e:
- log.warn("Could not connect to QEMU monitor: {}".format(e))
- return result
- try:
- tn.write(command.encode('ascii') + b"\n")
- time.sleep(0.1)
- except OSError as e:
- log.warn("Could not write to QEMU monitor: {}".format(e))
- tn.close()
- return result
- if expected:
- try:
- ind, match, dat = tn.expect(list=expected, timeout=timeout)
- if match:
- result = match
- except EOFError as e:
- log.warn("Could not read from QEMU monitor: {}".format(e))
- tn.close()
- return result
-
- def _get_vm_status(self):
- """
- Returns this VM suspend status (running|paused)
-
- :returns: status (string)
- """
-
- result = None
-
- match = self._control_vm("info status", [b"running", b"paused"])
- if match:
- result = match.group(0).decode('ascii')
- return result
-
- def suspend(self):
- """
- Suspends this QEMU VM.
- """
-
- vm_status = self._get_vm_status()
- if vm_status == "running":
- self._control_vm("stop")
- log.debug("QEMU VM has been suspended")
- else:
- log.info("QEMU VM is not running to be suspended, current status is {}".format(vm_status))
-
- def reload(self):
- """
- Reloads this QEMU VM.
- """
-
- self._control_vm("system_reset")
- log.debug("QEMU VM has been reset")
-
- def resume(self):
- """
- Resumes this QEMU VM.
- """
-
- vm_status = self._get_vm_status()
- if vm_status == "paused":
- self._control_vm("cont")
- log.debug("QEMU VM has been resumed")
- else:
- log.info("QEMU VM is not paused to be resumed, current status is {}".format(vm_status))
-
- def port_add_nio_binding(self, adapter_id, nio):
- """
- Adds a port NIO binding.
-
- :param adapter_id: adapter ID
- :param nio: NIO instance to add to the slot/port
- """
-
- try:
- adapter = self._ethernet_adapters[adapter_id]
- except IndexError:
- raise QemuError("Adapter {adapter_id} doesn't exist on QEMU VM {name}".format(name=self._name,
- adapter_id=adapter_id))
-
- if self.is_running():
- # dynamically configure an UDP tunnel on the QEMU VM adapter
- if nio and isinstance(nio, NIO_UDP):
- if self._legacy_networking:
- self._control_vm("host_net_remove {} gns3-{}".format(adapter_id, adapter_id))
- self._control_vm("host_net_add udp vlan={},name=gns3-{},sport={},dport={},daddr={}".format(adapter_id,
- adapter_id,
- nio.lport,
- nio.rport,
- nio.rhost))
- else:
- # FIXME: does it work? very undocumented feature...
- self._control_vm("netdev_del gns3-{}".format(adapter_id))
- self._control_vm("netdev_add socket,id=gns3-{},udp={}:{},localaddr={}:{}".format(adapter_id,
- nio.rhost,
- nio.rport,
- self._host,
- nio.lport))
-
- adapter.add_nio(0, nio)
- log.info("QEMU VM {name} [id={id}]: {nio} added to adapter {adapter_id}".format(name=self._name,
- id=self._id,
- nio=nio,
- adapter_id=adapter_id))
-
- def port_remove_nio_binding(self, adapter_id):
- """
- Removes a port NIO binding.
-
- :param adapter_id: adapter ID
-
- :returns: NIO instance
- """
-
- try:
- adapter = self._ethernet_adapters[adapter_id]
- except IndexError:
- raise QemuError("Adapter {adapter_id} doesn't exist on QEMU VM {name}".format(name=self._name,
- adapter_id=adapter_id))
-
- if self.is_running():
- # dynamically disable the QEMU VM adapter
- if self._legacy_networking:
- self._control_vm("host_net_remove {} gns3-{}".format(adapter_id, adapter_id))
- self._control_vm("host_net_add user vlan={},name=gns3-{}".format(adapter_id, adapter_id))
- else:
- # FIXME: does it work? very undocumented feature...
- self._control_vm("netdev_del gns3-{}".format(adapter_id))
- self._control_vm("netdev_add user,id=gns3-{}".format(adapter_id))
-
- nio = adapter.get_nio(0)
- adapter.remove_nio(0)
- log.info("QEMU VM {name} [id={id}]: {nio} removed from adapter {adapter_id}".format(name=self._name,
- id=self._id,
- nio=nio,
- adapter_id=adapter_id))
- return nio
-
- @property
- def started(self):
- """
- Returns either this QEMU VM has been started or not.
-
- :returns: boolean
- """
-
- return self._started
-
- def read_stdout(self):
- """
- Reads the standard output of the QEMU process.
- Only use when the process has been stopped or has crashed.
- """
-
- output = ""
- if self._stdout_file:
- try:
- with open(self._stdout_file, errors="replace") as file:
- output = file.read()
- except OSError as e:
- log.warn("could not read {}: {}".format(self._stdout_file, e))
- return output
-
- def is_running(self):
- """
- Checks if the QEMU process is running
-
- :returns: True or False
- """
-
- if self._process and self._process.poll() is None:
- return True
- return False
-
- def command(self):
- """
- Returns the QEMU command line.
-
- :returns: QEMU command line (string)
- """
-
- return " ".join(self._build_command())
-
- def _serial_options(self):
-
- if self._console:
- return ["-serial", "telnet:{}:{},server,nowait".format(self._console_host, self._console)]
- else:
- return []
-
- def _monitor_options(self):
-
- if self._monitor:
- return ["-monitor", "telnet:{}:{},server,nowait".format(self._monitor_host, self._monitor)]
- else:
- return []
-
- def _disk_options(self):
-
- options = []
- qemu_img_path = ""
- qemu_path_dir = os.path.dirname(self._qemu_path)
- try:
- for f in os.listdir(qemu_path_dir):
- if f.startswith("qemu-img"):
- qemu_img_path = os.path.join(qemu_path_dir, f)
- except OSError as e:
- raise QemuError("Error while looking for qemu-img in {}: {}".format(qemu_path_dir, e))
-
- if not qemu_img_path:
- raise QemuError("Could not find qemu-img in {}".format(qemu_path_dir))
-
- try:
- if self._hda_disk_image:
- if not os.path.isfile(self._hda_disk_image) or not os.path.exists(self._hda_disk_image):
- if os.path.islink(self._hda_disk_image):
- raise QemuError("hda disk image '{}' linked to '{}' is not accessible".format(self._hda_disk_image, os.path.realpath(self._hda_disk_image)))
- else:
- raise QemuError("hda disk image '{}' is not accessible".format(self._hda_disk_image))
- hda_disk = os.path.join(self._working_dir, "hda_disk.qcow2")
- if not os.path.exists(hda_disk):
- retcode = subprocess.call([qemu_img_path, "create", "-o",
- "backing_file={}".format(self._hda_disk_image),
- "-f", "qcow2", hda_disk])
- log.info("{} returned with {}".format(qemu_img_path, retcode))
- else:
- # create a "FLASH" with 256MB if no disk image has been specified
- hda_disk = os.path.join(self._working_dir, "flash.qcow2")
- if not os.path.exists(hda_disk):
- retcode = subprocess.call([qemu_img_path, "create", "-f", "qcow2", hda_disk, "128M"])
- log.info("{} returned with {}".format(qemu_img_path, retcode))
-
- except (OSError, subprocess.SubprocessError) as e:
- raise QemuError("Could not create disk image {}".format(e))
-
- options.extend(["-hda", hda_disk])
- if self._hdb_disk_image:
- if not os.path.isfile(self._hdb_disk_image) or not os.path.exists(self._hdb_disk_image):
- if os.path.islink(self._hdb_disk_image):
- raise QemuError("hdb disk image '{}' linked to '{}' is not accessible".format(self._hdb_disk_image, os.path.realpath(self._hdb_disk_image)))
- else:
- raise QemuError("hdb disk image '{}' is not accessible".format(self._hdb_disk_image))
- hdb_disk = os.path.join(self._working_dir, "hdb_disk.qcow2")
- if not os.path.exists(hdb_disk):
- try:
- retcode = subprocess.call([qemu_img_path, "create", "-o",
- "backing_file={}".format(self._hdb_disk_image),
- "-f", "qcow2", hdb_disk])
- log.info("{} returned with {}".format(qemu_img_path, retcode))
- except (OSError, subprocess.SubprocessError) as e:
- raise QemuError("Could not create disk image {}".format(e))
- options.extend(["-hdb", hdb_disk])
-
- return options
-
- def _linux_boot_options(self):
-
- options = []
- if self._initrd:
- if not os.path.isfile(self._initrd) or not os.path.exists(self._initrd):
- if os.path.islink(self._initrd):
- raise QemuError("initrd file '{}' linked to '{}' is not accessible".format(self._initrd, os.path.realpath(self._initrd)))
- else:
- raise QemuError("initrd file '{}' is not accessible".format(self._initrd))
- options.extend(["-initrd", self._initrd])
- if self._kernel_image:
- if not os.path.isfile(self._kernel_image) or not os.path.exists(self._kernel_image):
- if os.path.islink(self._kernel_image):
- raise QemuError("kernel image '{}' linked to '{}' is not accessible".format(self._kernel_image, os.path.realpath(self._kernel_image)))
- else:
- raise QemuError("kernel image '{}' is not accessible".format(self._kernel_image))
- options.extend(["-kernel", self._kernel_image])
- if self._kernel_command_line:
- options.extend(["-append", self._kernel_command_line])
-
- return options
-
- def _network_options(self):
-
- network_options = []
- adapter_id = 0
- for adapter in self._ethernet_adapters:
- # TODO: let users specify a base mac address
- mac = "00:00:ab:%02x:%02x:%02d" % (random.randint(0x00, 0xff), random.randint(0x00, 0xff), adapter_id)
- if self._legacy_networking:
- network_options.extend(["-net", "nic,vlan={},macaddr={},model={}".format(adapter_id, mac, self._adapter_type)])
- else:
- network_options.extend(["-device", "{},mac={},netdev=gns3-{}".format(self._adapter_type, mac, adapter_id)])
-
- nio = adapter.get_nio(0)
- if nio and isinstance(nio, NIO_UDP):
- if self._legacy_networking:
- network_options.extend(["-net", "udp,vlan={},name=gns3-{},sport={},dport={},daddr={}".format(adapter_id,
- adapter_id,
- nio.lport,
- nio.rport,
- nio.rhost)])
- else:
- network_options.extend(["-netdev", "socket,id=gns3-{},udp={}:{},localaddr={}:{}".format(adapter_id,
- nio.rhost,
- nio.rport,
- self._host,
- nio.lport)])
- else:
- if self._legacy_networking:
- network_options.extend(["-net", "user,vlan={},name=gns3-{}".format(adapter_id, adapter_id)])
- else:
- network_options.extend(["-netdev", "user,id=gns3-{}".format(adapter_id)])
- adapter_id += 1
-
- return network_options
-
- def _build_command(self):
- """
- Command to start the QEMU process.
- (to be passed to subprocess.Popen())
- """
-
- command = [self._qemu_path]
- command.extend(["-name", self._name])
- command.extend(["-m", str(self._ram)])
- command.extend(self._disk_options())
- command.extend(self._linux_boot_options())
- command.extend(self._serial_options())
- command.extend(self._monitor_options())
- additional_options = self._options.strip()
- if additional_options:
- command.extend(shlex.split(additional_options))
- command.extend(self._network_options())
- return command
diff --git a/gns3server/old_modules/qemu/schemas.py b/gns3server/old_modules/qemu/schemas.py
deleted file mode 100644
index 32b09664..00000000
--- a/gns3server/old_modules/qemu/schemas.py
+++ /dev/null
@@ -1,423 +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 .
-
-
-QEMU_CREATE_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to create a new QEMU VM instance",
- "type": "object",
- "properties": {
- "name": {
- "description": "QEMU VM instance name",
- "type": "string",
- "minLength": 1,
- },
- "qemu_path": {
- "description": "Path to QEMU",
- "type": "string",
- "minLength": 1,
- },
- "qemu_id": {
- "description": "QEMU VM instance ID",
- "type": "integer"
- },
- "console": {
- "description": "console TCP port",
- "minimum": 1,
- "maximum": 65535,
- "type": "integer"
- },
- "monitor": {
- "description": "monitor TCP port",
- "minimum": 1,
- "maximum": 65535,
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["name", "qemu_path"],
-}
-
-QEMU_DELETE_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to delete a QEMU VM instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "QEMU VM instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-QEMU_UPDATE_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to update a QEMU VM instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "QEMU VM instance ID",
- "type": "integer"
- },
- "name": {
- "description": "QEMU VM instance name",
- "type": "string",
- "minLength": 1,
- },
- "qemu_path": {
- "description": "path to QEMU",
- "type": "string",
- "minLength": 1,
- },
- "hda_disk_image": {
- "description": "QEMU hda disk image path",
- "type": "string",
- },
- "hdb_disk_image": {
- "description": "QEMU hdb disk image path",
- "type": "string",
- },
- "ram": {
- "description": "amount of RAM in MB",
- "type": "integer"
- },
- "adapters": {
- "description": "number of adapters",
- "type": "integer",
- "minimum": 0,
- "maximum": 32,
- },
- "adapter_type": {
- "description": "QEMU adapter type",
- "type": "string",
- "minLength": 1,
- },
- "console": {
- "description": "console TCP port",
- "minimum": 1,
- "maximum": 65535,
- "type": "integer"
- },
- "monitor": {
- "description": "monitor TCP port",
- "minimum": 1,
- "maximum": 65535,
- "type": "integer"
- },
- "initrd": {
- "description": "QEMU initrd path",
- "type": "string",
- },
- "kernel_image": {
- "description": "QEMU kernel image path",
- "type": "string",
- },
- "kernel_command_line": {
- "description": "QEMU kernel command line",
- "type": "string",
- },
- "cloud_path": {
- "description": "Path to the image in the cloud object store",
- "type": "string",
- },
- "legacy_networking": {
- "description": "Use QEMU legagy networking commands (-net syntax)",
- "type": "boolean",
- },
- "cpu_throttling": {
- "description": "Percentage of CPU allowed for QEMU",
- "minimum": 0,
- "maximum": 800,
- "type": "integer",
- },
- "process_priority": {
- "description": "Process priority for QEMU",
- "enum": ["realtime",
- "very high",
- "high",
- "normal",
- "low",
- "very low"]
- },
- "options": {
- "description": "Additional QEMU options",
- "type": "string",
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-QEMU_START_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to start a QEMU VM instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "QEMU VM instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-QEMU_STOP_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to stop a QEMU VM instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "QEMU VM instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-QEMU_SUSPEND_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to suspend a QEMU VM instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "QEMU VM instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-QEMU_RELOAD_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to reload a QEMU VM instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "QEMU VM instance ID",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id"]
-}
-
-QEMU_ALLOCATE_UDP_PORT_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to allocate an UDP port for a QEMU VM instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "QEMU VM instance ID",
- "type": "integer"
- },
- "port_id": {
- "description": "Unique port identifier for the QEMU VM instance",
- "type": "integer"
- },
- },
- "additionalProperties": False,
- "required": ["id", "port_id"]
-}
-
-QEMU_ADD_NIO_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to add a NIO for a QEMU 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": "QEMU VM instance ID",
- "type": "integer"
- },
- "port_id": {
- "description": "Unique port identifier for the QEMU VM instance",
- "type": "integer"
- },
- "port": {
- "description": "Port number",
- "type": "integer",
- "minimum": 0,
- "maximum": 32
- },
- "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"]
-}
-
-
-QEMU_DELETE_NIO_SCHEMA = {
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Request validation to delete a NIO for a QEMU VM instance",
- "type": "object",
- "properties": {
- "id": {
- "description": "QEMU VM instance ID",
- "type": "integer"
- },
- "port": {
- "description": "Port number",
- "type": "integer",
- "minimum": 0,
- "maximum": 32
- },
- },
- "additionalProperties": False,
- "required": ["id", "port"]
-}