Refactoring to use a common node class for all VMs and other (future) objects.

This commit is contained in:
grossmj committed 2016-05-11 11:35:36 -06:00
1 parent 9dca7dfe4a
commit 5a76f81271
102 files changed
+1654 -1672

No files matched your search

+64 -64
View File
@@ -40,14 +40,14 @@ from .nios.nio_tap import NIOTAP
from .nios.nio_nat import NIONAT
from .nios.nio_generic_ethernet import NIOGenericEthernet
from ..utils.images import md5sum, remove_checksum
from .vm_error import VMError
from .node_error import NodeError
class BaseManager:
"""
Base class for all Manager classes.
Responsible of management of a VM pool of the same type.
Responsible of management of a node pool of the same type.
"""
_convert_lock = None
@@ -55,7 +55,7 @@ class BaseManager:
def __init__(self):
BaseManager._convert_lock = asyncio.Lock()
self._vms = {}
self._nodes = {}
self._port_manager = None
self._config = Config.instance()
@@ -110,8 +110,8 @@ class BaseManager:
def unload(self):
tasks = []
for vm_id in self._vms.keys():
tasks.append(asyncio.async(self.close_vm(vm_id)))
for node_id in self._nodes.keys():
tasks.append(asyncio.async(self.close_node(node_id)))
if tasks:
done, _ = yield from asyncio.wait(tasks)
@@ -119,21 +119,21 @@ class BaseManager:
try:
future.result()
except (Exception, GeneratorExit) as e:
log.error("Could not close VM {}".format(e), exc_info=1)
log.error("Could not close node {}".format(e), exc_info=1)
continue
if hasattr(BaseManager, "_instance"):
BaseManager._instance = None
log.debug("Module {} unloaded".format(self.module_name))
def get_vm(self, vm_id, project_id=None):
def get_node(self, node_id, project_id=None):
"""
Returns a VM instance.
Returns a Node instance.
:param vm_id: VM identifier
:param node_id: Node identifier
:param project_id: Project identifier
:returns: VM instance
:returns: Node instance
"""
if project_id:
@@ -141,19 +141,19 @@ class BaseManager:
project = ProjectManager.instance().get_project(project_id)
try:
UUID(vm_id, version=4)
UUID(node_id, version=4)
except ValueError:
raise aiohttp.web.HTTPBadRequest(text="VM ID {} is not a valid UUID".format(vm_id))
raise aiohttp.web.HTTPBadRequest(text="Node ID {} is not a valid UUID".format(node_id))
if vm_id not in self._vms:
raise aiohttp.web.HTTPNotFound(text="VM ID {} doesn't exist".format(vm_id))
if node_id not in self._nodes:
raise aiohttp.web.HTTPNotFound(text="Node ID {} doesn't exist".format(node_id))
vm = self._vms[vm_id]
node = self._nodes[node_id]
if project_id:
if vm.project.id != project.id:
raise aiohttp.web.HTTPNotFound(text="Project ID {} doesn't belong to VM {}".format(project_id, vm.name))
if node.project.id != project.id:
raise aiohttp.web.HTTPNotFound(text="Project ID {} doesn't belong to node {}".format(project_id, node.name))
return vm
return node
@asyncio.coroutine
def convert_old_project(self, project, legacy_id, name):
@@ -194,8 +194,8 @@ class BaseManager:
new_remote_project_path, e))
if hasattr(self, "get_legacy_vm_workdir"):
# rename old project VM working dir
log.info("Converting old VM working directory...")
# rename old project node working dir
log.info("Converting old node working directory...")
legacy_vm_dir = self.get_legacy_vm_workdir(legacy_id, name)
legacy_vm_working_path = os.path.join(new_project_files_path, legacy_vm_dir)
new_vm_working_path = os.path.join(new_project_files_path, self.module_name.lower(), new_id)
@@ -204,57 +204,58 @@ class BaseManager:
log.info('Moving "{}" to "{}"'.format(legacy_vm_working_path, new_vm_working_path))
yield from wait_run_in_executor(shutil.move, legacy_vm_working_path, new_vm_working_path)
except OSError as e:
raise aiohttp.web.HTTPInternalServerError(text="Could not move VM working directory: {} to {} {}".format(legacy_vm_working_path,
new_vm_working_path, e))
raise aiohttp.web.HTTPInternalServerError(text="Could not move vm working directory: {} to {} {}".format(legacy_vm_working_path,
new_vm_working_path,e))
return new_id
@asyncio.coroutine
def create_vm(self, name, project_id, vm_id, *args, **kwargs):
def create_node(self, name, project_id, node_id, *args, **kwargs):
"""
Create a new VM
Create a new node
:param name: VM name
:param name: Node name
:param project_id: Project identifier
:param vm_id: restore a VM identifier
:param node_id: restore a node identifier
"""
if vm_id in self._vms:
return self._vms[vm_id]
if node_id in self._nodes:
return self._nodes[node_id]
project = ProjectManager.instance().get_project(project_id)
if vm_id and isinstance(vm_id, int):
if node_id and isinstance(node_id, int):
# old project
with (yield from BaseManager._convert_lock):
vm_id = yield from self.convert_old_project(project, vm_id, name)
node_id = yield from self.convert_old_project(project, node_id, name)
if not vm_id:
vm_id = str(uuid4())
if not node_id:
node_id = str(uuid4())
vm = self._VM_CLASS(name, vm_id, project, self, *args, **kwargs)
if asyncio.iscoroutinefunction(vm.create):
yield from vm.create()
node = self._NODE_CLASS(name, node_id, project, self, *args, **kwargs)
if asyncio.iscoroutinefunction(node.create):
yield from node.create()
else:
vm.create()
self._vms[vm.id] = vm
project.add_vm(vm)
return vm
node.create()
self._nodes[node.id] = node
project.add_node(node)
return node
@asyncio.coroutine
def close_vm(self, vm_id):
def close_node(self, node_id):
"""
Close a VM
Close a node
:param vm_id: VM identifier
:param node_id: Node identifier
:returns: VM instance
:returns: Node instance
"""
vm = self.get_vm(vm_id)
if asyncio.iscoroutinefunction(vm.close):
yield from vm.close()
node = self.get_node(node_id)
if asyncio.iscoroutinefunction(node.close):
yield from node.close()
else:
vm.close()
return vm
node.close()
return node
@asyncio.coroutine
def project_closing(self, project):
@@ -274,9 +275,9 @@ class BaseManager:
:param project: Project instance
"""
for vm in project.vms:
if vm.id in self._vms:
del self._vms[vm.id]
for node in project.nodes:
if node.id in self._nodes:
del self._nodes[node.id]
@asyncio.coroutine
def project_moved(self, project):
@@ -299,20 +300,19 @@ class BaseManager:
pass
@asyncio.coroutine
def delete_vm(self, vm_id):
def delete_node(self, node_id):
"""
Delete a VM. VM working directory will be destroy when
we receive a commit.
Delete a node. The node working directory will be destroyed when a commit is received.
:param vm_id: VM identifier
:returns: VM instance
:param node_id: Node identifier
:returns: Node instance
"""
vm = yield from self.close_vm(vm_id)
vm.project.mark_vm_for_destruction(vm)
if vm.id in self._vms:
del self._vms[vm.id]
return vm
node = yield from self.close_node(node_id)
node.project.mark_node_for_destruction(node)
if node.id in self._nodes:
del self._nodes[node.id]
return node
@staticmethod
def has_privileged_access(executable):
@@ -408,7 +408,7 @@ class BaseManager:
# Windows path should not be send to a unix server
if not sys.platform.startswith("win"):
if re.match(r"^[A-Z]:", path) is not None:
raise VMError("{} is not allowed on this remote server. Please use only a filename in {}.".format(path, img_directory))
raise NodeError("{} is not allowed on this remote server. Please use only a filename in {}.".format(path, img_directory))
if not os.path.isabs(path):
s = os.path.split(path)
@@ -429,7 +429,7 @@ class BaseManager:
img_directory = force_unix_path(img_directory)
path = force_unix_path(path)
if len(os.path.commonprefix([img_directory, path])) < len(img_directory):
raise VMError("{} is not allowed on this remote server. Please use only a filename in {}.".format(path, img_directory))
raise NodeError("{} is not allowed on this remote server. Please use only a filename in {}.".format(path, img_directory))
return force_unix_path(path)
@@ -454,7 +454,7 @@ class BaseManager:
@asyncio.coroutine
def list_images(self):
"""
Return the list of available images for this VM type
Return the list of available images for this node type
:returns: Array of hash
"""
@@ -24,34 +24,33 @@ import tempfile
import psutil
import platform
from gns3server.utils import parse_version
from ..utils.asyncio import wait_run_in_executor
from ..ubridge.hypervisor import Hypervisor
from .vm_error import VMError
from .node_error import NodeError
log = logging.getLogger(__name__)
class BaseVM:
class BaseNode:
"""
Base vm implementation.
Base node implementation.
:param name: name of this IOU vm
:param vm_id: IOU instance identifier
:param name: name of this node
:param node_id: Node instance identifier
:param project: Project instance
:param manager: parent VM Manager
:param manager: parent node manager
:param console: TCP console port
:param aux: TCP aux console port
:param allocate_aux: Boolean if true will allocate an aux console port
"""
def __init__(self, name, vm_id, project, manager, console=None, console_type="telnet", aux=None, allocate_aux=False):
def __init__(self, name, node_id, project, manager, console=None, console_type="telnet", aux=None, allocate_aux=False):
self._name = name
self._usage = ""
self._id = vm_id
self._id = node_id
self._project = project
self._manager = manager
self._console = console
@@ -61,7 +60,7 @@ class BaseVM:
self._hw_virtualization = False
self._ubridge_hypervisor = None
self._closed = False
self._vm_status = "stopped"
self._node_status = "stopped"
self._command_line = ""
self._allocate_aux = allocate_aux
@@ -98,19 +97,19 @@ class BaseVM:
@property
def status(self):
"""Return current VM status"""
"""Return current node status"""
return self._vm_status
return self._node_status
@status.setter
def status(self, status):
self._vm_status = status
self._project.emit("vm.{}".format(status), self)
self._node_status = status
self._project.emit("node.{}".format(status), self)
@property
def command_line(self):
"""Return command used to start the VM"""
"""Return command used to start the node"""
return self._command_line
@@ -122,7 +121,7 @@ class BaseVM:
@property
def project(self):
"""
Returns the VM current project.
Returns the node current project.
:returns: Project instance.
"""
@@ -132,7 +131,7 @@ class BaseVM:
@property
def name(self):
"""
Returns the name for this VM.
Returns the name for this node.
:returns: name
"""
@@ -142,7 +141,7 @@ class BaseVM:
@name.setter
def name(self, new_name):
"""
Sets the name of this VM.
Sets the name of this node.
:param new_name: name
"""
@@ -156,7 +155,7 @@ class BaseVM:
@property
def usage(self):
"""
Returns the usage for this VM.
Returns the usage for this node.
:returns: usage
"""
@@ -166,7 +165,7 @@ class BaseVM:
@usage.setter
def usage(self, new_usage):
"""
Sets the usage of this VM.
Sets the usage of this node.
:param new_usage: usage
"""
@@ -176,9 +175,9 @@ class BaseVM:
@property
def id(self):
"""
Returns the ID for this VM.
Returns the ID for this node.
:returns: VM identifier (string)
:returns: Node identifier (string)
"""
return self._id
@@ -186,7 +185,7 @@ class BaseVM:
@property
def manager(self):
"""
Returns the manager for this VM.
Returns the manager for this node.
:returns: instance of manager
"""
@@ -196,10 +195,10 @@ class BaseVM:
@property
def working_dir(self):
"""
Return VM working directory
Return the node working directory
"""
return self._project.vm_working_directory(self)
return self._project.node_working_directory(self)
@property
def temporary_directory(self):
@@ -207,43 +206,43 @@ class BaseVM:
try:
self._temporary_directory = tempfile.mkdtemp()
except OSError as e:
raise VMError("Can't create temporary directory: {}".format(e))
raise NodeError("Can't create temporary directory: {}".format(e))
return self._temporary_directory
def create(self):
"""
Creates the VM.
Creates the node.
"""
log.info("{module}: {name} [{id}] created".format(module=self.manager.module_name,
name=self.name,
id=self.id))
self._project.emit("vm.created", self)
self._project.emit("node.created", self)
@asyncio.coroutine
def delete(self):
"""
Delete the VM (including all its files).
Delete the node (including all its files).
"""
self._project.emit("vm.deleted", self)
directory = self.project.vm_working_directory(self)
self._project.emit("node.deleted", self)
directory = self.project.node_working_directory(self)
if os.path.exists(directory):
try:
yield from wait_run_in_executor(shutil.rmtree, directory)
except OSError as e:
raise aiohttp.web.HTTPInternalServerError(text="Could not delete the VM working directory: {}".format(e))
raise aiohttp.web.HTTPInternalServerError(text="Could not delete the node working directory: {}".format(e))
def start(self):
"""
Starts the VM process.
Starts the node process.
"""
raise NotImplementedError
def stop(self):
"""
Starts the VM process.
Starts the node process.
"""
raise NotImplementedError
@@ -251,7 +250,7 @@ class BaseVM:
@asyncio.coroutine
def close(self):
"""
Close the VM process.
Close the node process.
"""
if self._closed:
@@ -290,7 +289,7 @@ class BaseVM:
@property
def aux(self):
"""
Returns the aux console port of this VM.
Returns the aux console port of this node.
:returns: aux console port
"""
@@ -321,7 +320,7 @@ class BaseVM:
@property
def console(self):
"""
Returns the console port of this VM.
Returns the console port of this node.
:returns: console port
"""
@@ -340,7 +339,7 @@ class BaseVM:
return
if self._console_type == "vnc" and console is not None and console < 5900:
raise VMError("VNC console require a port superior or equal to 5900 currently it's {}".format(console))
raise NodeError("VNC console require a port superior or equal to 5900 currently it's {}".format(console))
if self._console:
self._manager.port_manager.release_tcp_port(self._console, self._project)
@@ -359,7 +358,7 @@ class BaseVM:
@property
def console_type(self):
"""
Returns the console type for this VM.
Returns the console type for this node.
:returns: console type (string)
"""
@@ -369,15 +368,11 @@ class BaseVM:
@console_type.setter
def console_type(self, console_type):
"""
Sets the console type for this VM.
Sets the console type for this node.
:param console_type: console type (string)
"""
log.info('QEMU VM "{name}" [{id}] has set the console type to {console_type}'.format(name=self._name,
id=self._id,
console_type=console_type))
if console_type != self._console_type:
# get a new port if the console type change
self._manager.port_manager.release_tcp_port(self._console, self._project)
@@ -406,17 +401,17 @@ class BaseVM:
path = shutil.which("ubridge")
if path is None or len(path) == 0:
raise VMError("uBridge is not installed")
raise NodeError("uBridge is not installed")
return path
@asyncio.coroutine
def _start_ubridge(self):
"""
Starts uBridge (handles connections to and from this VMware VM).
Starts uBridge (handles connections to and from this node).
"""
if not self._manager.has_privileged_access(self.ubridge_path):
raise VMError("uBridge requires root access or capability to interact with network adapters")
raise NodeError("uBridge requires root access or capability to interact with network adapters")
server_config = self._manager.config.get_section_config("Server")
server_host = server_config.get("host")
@@ -430,7 +425,7 @@ class BaseVM:
@property
def hw_virtualization(self):
"""
Returns either the VM is using hardware virtualization or not.
Returns either the node is using hardware virtualization or not.
:return: boolean
"""
+1 -1
View File
@@ -37,7 +37,7 @@ DOCKER_MINIMUM_API_VERSION = "1.21"
class Docker(BaseManager):
_VM_CLASS = DockerVM
_NODE_CLASS = DockerVM
def __init__(self):
super().__init__()
+2 -2
View File
@@ -19,10 +19,10 @@
Custom exceptions for the Docker module.
"""
from ..vm_error import VMError
from ..node_error import NodeError
class DockerError(VMError):
class DockerError(NodeError):
pass
+8 -9
View File
@@ -27,9 +27,8 @@ import aiohttp
import json
import os
from ...ubridge.hypervisor import Hypervisor
from .docker_error import *
from ..base_vm import BaseVM
from ..base_node import BaseNode
from ..adapters.ethernet_adapter import EthernetAdapter
from ..nios.nio_udp import NIOUDP
from ...utils.asyncio.telnet_server import AsyncioTelnetServer
@@ -43,11 +42,11 @@ import logging
log = logging.getLogger(__name__)
class DockerVM(BaseVM):
class DockerVM(BaseNode):
"""Docker container implementation.
:param name: Docker container name
:param vm_id: Docker VM identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Manager instance
:param image: Docker image
@@ -59,11 +58,11 @@ class DockerVM(BaseVM):
:param console_http_path: Url part with the path of the web interface
"""
def __init__(self, name, vm_id, project, manager, image,
def __init__(self, name, node_id, project, manager, image,
console=None, aux=None, start_command=None,
adapters=None, environment=None, console_type="telnet",
console_resolution="1024x768", console_http_port=80, console_http_path="/"):
super().__init__(name, vm_id, project, manager, console=console, aux=aux, allocate_aux=True, console_type=console_type)
super().__init__(name, node_id, project, manager, console=console, aux=aux, allocate_aux=True, console_type=console_type)
self._image = image
self._start_command = start_command
@@ -93,7 +92,7 @@ class DockerVM(BaseVM):
def __json__(self):
return {
"name": self._name,
"vm_id": self._id,
"node_id": self._id,
"container_id": self._cid,
"project_id": self._project.id,
"image": self._image,
@@ -757,7 +756,7 @@ class DockerVM(BaseVM):
adapter = "bridge{}".format(adapter_number)
if not self._ubridge_hypervisor or not self._ubridge_hypervisor.is_running():
raise VMwareError("Cannot start the packet capture: uBridge is not running")
raise DockerError("Cannot start the packet capture: uBridge is not running")
yield from self._ubridge_hypervisor.send('bridge start_capture {name} "{output_file}"'.format(name=adapter, output_file=output_file))
@asyncio.coroutine
@@ -770,7 +769,7 @@ class DockerVM(BaseVM):
adapter = "bridge{}".format(adapter_number)
if not self._ubridge_hypervisor or not self._ubridge_hypervisor.is_running():
raise VMwareError("Cannot stop the packet capture: uBridge is not running")
raise DockerError("Cannot stop the packet capture: uBridge is not running")
yield from self._ubridge_hypervisor.send("bridge stop_capture {name}".format(name=adapter))
@asyncio.coroutine
+8 -9
View File
@@ -102,7 +102,7 @@ WIC_MATRIX = {"WIC-1ENET": WIC_1ENET,
class Dynamips(BaseManager):
_VM_CLASS = DynamipsVM
_NODE_CLASS = DynamipsVM
_DEVICE_CLASS = DynamipsDevice
_ghost_ios_lock = None
@@ -142,7 +142,7 @@ class Dynamips(BaseManager):
def release_dynamips_id(self, project_id, dynamips_id):
"""
A dynamips id can be reused by another vm
A Dynamips id can be reused by another VM
:param project_id: UUID of the project
:param dynamips_id: Asked id
@@ -231,9 +231,9 @@ class Dynamips(BaseManager):
:param project: Project instance
"""
for vm in self._vms.values():
if vm.project.id == project.id:
yield from vm.hypervisor.set_working_dir(project.module_working_directory(self.module_name.lower()))
for node in self._nodes.values():
if node.project.id == project.id:
yield from node.hypervisor.set_working_dir(project.module_working_directory(self.module_name.lower()))
for device in self._devices.values():
if device.project.id == project.id:
@@ -248,10 +248,10 @@ class Dynamips(BaseManager):
"""
# save the configs when the project is committed
for vm in self._vms.copy().values():
if vm.project.id == project.id:
for node in self._nodes.copy().values():
if node.project.id == project.id:
try:
yield from vm.save_configs()
yield from node.save_configs()
except DynamipsError as e:
log.warning(e)
continue
@@ -273,7 +273,6 @@ class Dynamips(BaseManager):
:param name: Device name
:param project_id: Project identifier
:param vm_id: restore a VM identifier
"""
project = ProjectManager.instance().get_project(project_id)
@@ -19,9 +19,9 @@
Custom exceptions for the Dynamips module.
"""
from ..vm_error import VMError
from ..node_error import NodeError
class DynamipsError(VMError):
class DynamipsError(NodeError):
pass
+2 -2
View File
@@ -43,9 +43,9 @@ class DynamipsVM:
Factory to create an Router object based on the correct platform.
"""
def __new__(cls, name, vm_id, project, manager, dynamips_id, platform, **kwargs):
def __new__(cls, name, node_id, project, manager, dynamips_id, platform, **kwargs):
if platform not in PLATFORMS:
raise DynamipsError("Unknown router platform: {}".format(platform))
return PLATFORMS[platform](name, vm_id, project, manager, dynamips_id, **kwargs)
return PLATFORMS[platform](name, node_id, project, manager, dynamips_id, **kwargs)
+3 -3
View File
@@ -35,7 +35,7 @@ class C1700(Router):
Dynamips c1700 router.
:param name: The name of this router
:param vm_id: Router instance identifier
:param node_id: Node instance identifier
:param project: Project instance
:param manager: Parent VM Manager
:param dynamips_id: ID to use with Dynamips
@@ -46,9 +46,9 @@ class C1700(Router):
1710 is not supported.
"""
def __init__(self, name, vm_id, project, manager, dynamips_id, console=None, aux=None, chassis="1720"):
def __init__(self, name, node_id, project, manager, dynamips_id, console=None, aux=None, chassis="1720"):
super().__init__(name, vm_id, project, manager, dynamips_id, console, aux, platform="c1700")
super().__init__(name, node_id, project, manager, dynamips_id, console, aux, platform="c1700")
# Set default values for this platform (must be the same as Dynamips)
self._ram = 64
+3 -3
View File
@@ -37,7 +37,7 @@ class C2600(Router):
Dynamips c2600 router.
:param name: The name of this router
:param vm_id: Router instance identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Parent VM Manager
:param dynamips_id: ID to use with Dynamips
@@ -61,9 +61,9 @@ class C2600(Router):
"2650XM": C2600_MB_1FE,
"2651XM": C2600_MB_2FE}
def __init__(self, name, vm_id, project, manager, dynamips_id, console=None, aux=None, chassis="2610"):
def __init__(self, name, node_id, project, manager, dynamips_id, console=None, aux=None, chassis="2610"):
super().__init__(name, vm_id, project, manager, dynamips_id, console, aux, platform="c2600")
super().__init__(name, node_id, project, manager, dynamips_id, console, aux, platform="c2600")
# Set default values for this platform (must be the same as Dynamips)
self._ram = 64
+3 -3
View File
@@ -35,7 +35,7 @@ class C2691(Router):
Dynamips c2691 router.
:param name: The name of this router
:param vm_id: Router instance identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Parent VM Manager
:param dynamips_id: ID to use with Dynamips
@@ -43,9 +43,9 @@ class C2691(Router):
:param aux: auxiliary console port
"""
def __init__(self, name, vm_id, project, manager, dynamips_id, console=None, aux=None, chassis=None):
def __init__(self, name, node_id, project, manager, dynamips_id, console=None, aux=None, chassis=None):
super().__init__(name, vm_id, project, manager, dynamips_id, console, aux, platform="c2691")
super().__init__(name, node_id, project, manager, dynamips_id, console, aux, platform="c2691")
# Set default values for this platform (must be the same as Dynamips)
self._ram = 128
+3 -3
View File
@@ -34,7 +34,7 @@ class C3600(Router):
Dynamips c3600 router.
:param name: The name of this router
:param vm_id: Router instance identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Parent VM Manager
:param dynamips_id: ID to use with Dynamips
@@ -44,9 +44,9 @@ class C3600(Router):
3620, 3640 or 3660 (default = 3640).
"""
def __init__(self, name, vm_id, project, manager, dynamips_id, console=None, aux=None, chassis="3640"):
def __init__(self, name, node_id, project, manager, dynamips_id, console=None, aux=None, chassis="3640"):
super().__init__(name, vm_id, project, manager, dynamips_id, console, aux, platform="c3600")
super().__init__(name, node_id, project, manager, dynamips_id, console, aux, platform="c3600")
# Set default values for this platform (must be the same as Dynamips)
self._ram = 128
+3 -3
View File
@@ -35,7 +35,7 @@ class C3725(Router):
Dynamips c3725 router.
:param name: The name of this router
:param vm_id: Router instance identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Parent VM Manager
:param dynamips_id: ID to use with Dynamips
@@ -43,9 +43,9 @@ class C3725(Router):
:param aux: auxiliary console port
"""
def __init__(self, name, vm_id, project, manager, dynamips_id, console=None, aux=None, chassis=None):
def __init__(self, name, node_id, project, manager, dynamips_id, console=None, aux=None, chassis=None):
super().__init__(name, vm_id, project, manager, dynamips_id, console, aux, platform="c3725")
super().__init__(name, node_id, project, manager, dynamips_id, console, aux, platform="c3725")
# Set default values for this platform (must be the same as Dynamips)
self._ram = 128
+3 -3
View File
@@ -35,7 +35,7 @@ class C3745(Router):
Dynamips c3745 router.
:param name: The name of this router
:param vm_id: Router instance identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Parent VM Manager
:param dynamips_id: ID to use with Dynamips
@@ -43,9 +43,9 @@ class C3745(Router):
:param aux: auxiliary console port
"""
def __init__(self, name, vm_id, project, manager, dynamips_id, console=None, aux=None, chassis=None):
def __init__(self, name, node_id, project, manager, dynamips_id, console=None, aux=None, chassis=None):
super().__init__(name, vm_id, project, manager, dynamips_id, console, aux, platform="c3745")
super().__init__(name, node_id, project, manager, dynamips_id, console, aux, platform="c3745")
# Set default values for this platform (must be the same as Dynamips)
self._ram = 128
+3 -3
View File
@@ -37,7 +37,7 @@ class C7200(Router):
Dynamips c7200 router (model is 7206).
:param name: The name of this router
:param vm_id: Router instance identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Parent VM Manager
:param dynamips_id: ID to use with Dynamips
@@ -46,9 +46,9 @@ class C7200(Router):
:param npe: Default NPE
"""
def __init__(self, name, vm_id, project, manager, dynamips_id, console=None, aux=None, npe="npe-400", chassis=None):
def __init__(self, name, node_id, project, manager, dynamips_id, console=None, aux=None, npe="npe-400", chassis=None):
super().__init__(name, vm_id, project, manager, dynamips_id, console, aux, platform="c7200")
super().__init__(name, node_id, project, manager, dynamips_id, console, aux, platform="c7200")
# Set default values for this platform (must be the same as Dynamips)
self._ram = 256
+1 -1
View File
@@ -69,7 +69,7 @@ class Device:
@name.setter
def name(self, new_name):
"""
Sets the name of this VM.
Sets the name of this device.
:param new_name: name
"""
+7 -7
View File
@@ -31,7 +31,7 @@ import binascii
import logging
log = logging.getLogger(__name__)
from ...base_vm import BaseVM
from ...base_node import BaseNode
from ..dynamips_error import DynamipsError
from ..nios.nio_udp import NIOUDP
@@ -39,13 +39,13 @@ from gns3server.utils.asyncio import wait_run_in_executor, monitor_process
from gns3server.utils.images import md5sum
class Router(BaseVM):
class Router(BaseNode):
"""
Dynamips router implementation.
:param name: The name of this router
:param vm_id: Router instance identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Parent VM Manager
:param dynamips_id: ID to use with Dynamips
@@ -59,11 +59,11 @@ class Router(BaseVM):
2: "running",
3: "suspended"}
def __init__(self, name, vm_id, project, manager, dynamips_id=None, console=None, aux=None, platform="c7200", hypervisor=None, ghost_flag=False):
def __init__(self, name, node_id, project, manager, dynamips_id=None, console=None, aux=None, platform="c7200", hypervisor=None, ghost_flag=False):
allocate_aux = manager.config.get_section_config("Dynamips").getboolean("allocate_aux_console_ports", False)
super().__init__(name, vm_id, project, manager, console=console, aux=aux, allocate_aux=aux)
super().__init__(name, node_id, project, manager, console=console, aux=aux, allocate_aux=aux)
self._hypervisor = hypervisor
self._dynamips_id = dynamips_id
@@ -111,7 +111,7 @@ class Router(BaseVM):
def __json__(self):
router_info = {"name": self.name,
"vm_id": self.id,
"node_id": self.id,
"vm_directory": os.path.join(self.project.module_working_directory(self.manager.module_name.lower())),
"project_id": self.project.id,
"dynamips_id": self._dynamips_id,
@@ -1549,7 +1549,7 @@ class Router(BaseVM):
def delete(self):
"""
Delete the VM (including all its files).
Delete this VM (including all its files).
"""
# delete the VM files
+21 -21
View File
@@ -32,7 +32,7 @@ log = logging.getLogger(__name__)
class IOU(BaseManager):
_VM_CLASS = IOUVM
_NODE_CLASS = IOUVM
def __init__(self):
@@ -41,35 +41,35 @@ class IOU(BaseManager):
self._used_application_ids = {}
@asyncio.coroutine
def create_vm(self, *args, **kwargs):
def create_node(self, *args, **kwargs):
"""
Creates a new IOU VM.
:returns: IOUVM instance
"""
vm = yield from super().create_vm(*args, **kwargs)
node = yield from super().create_node(*args, **kwargs)
try:
self._used_application_ids[vm.id] = self._free_application_ids.pop(0)
self._used_application_ids[node.id] = self._free_application_ids.pop(0)
except IndexError:
raise IOUError("Cannot create a new IOU VM (limit of 512 VMs reached on this host)")
return vm
return node
@asyncio.coroutine
def close_vm(self, vm_id, *args, **kwargs):
def close_node(self, node_id, *args, **kwargs):
"""
Closes an IOU VM.
:returns: IOUVM instance
"""
vm = self.get_vm(vm_id)
if vm_id in self._used_application_ids:
i = self._used_application_ids[vm_id]
node = self.get_node(node_id)
if node_id in self._used_application_ids:
i = self._used_application_ids[node_id]
self._free_application_ids.insert(0, i)
del self._used_application_ids[vm_id]
yield from super().close_vm(vm_id, *args, **kwargs)
return vm
del self._used_application_ids[node_id]
yield from super().close_node(node_id, *args, **kwargs)
return node
@asyncio.coroutine
def project_committed(self, project):
@@ -80,32 +80,32 @@ class IOU(BaseManager):
"""
# save the configs when the project is committed
for vm in self._vms.copy().values():
if vm.project.id == project.id:
for node in self._nodes.copy().values():
if node.project.id == project.id:
try:
vm.save_configs()
node.save_configs()
except IOUError as e:
log.warning(e)
continue
def get_application_id(self, vm_id):
def get_application_id(self, node_id):
"""
Get an unique application identifier for IOU.
:param vm_id: IOU VM identifier
:param node_id: Node identifier
:returns: IOU application identifier
"""
return self._used_application_ids.get(vm_id, 1)
return self._used_application_ids.get(node_id, 1)
@staticmethod
def get_legacy_vm_workdir(legacy_vm_id, name):
"""
Returns the name of the legacy working directory (pre 1.3) name for a VM.
Returns the name of the legacy working directory (pre 1.3) name for a node.
:param legacy_vm_id: legacy VM identifier (integer)
:param name: VM name (not used)
:param legacy_vm_id: legacy node identifier (integer)
:param name: Node name (not used)
:returns: working directory name
"""
+2 -2
View File
@@ -19,8 +19,8 @@
Custom exceptions for the IOU module.
"""
from ..vm_error import VMError
from ..node_error import NodeError
class IOUError(VMError):
class IOUError(NodeError):
pass
+7 -7
View File
@@ -42,7 +42,7 @@ from ..adapters.serial_adapter import SerialAdapter
from ..nios.nio_udp import NIOUDP
from ..nios.nio_tap import NIOTAP
from ..nios.nio_generic_ethernet import NIOGenericEthernet
from ..base_vm import BaseVM
from ..base_node import BaseNode
from .utils.iou_import import nvram_import
from .utils.iou_export import nvram_export
from .ioucon import start_ioucon
@@ -55,22 +55,22 @@ import sys
log = logging.getLogger(__name__)
class IOUVM(BaseVM):
class IOUVM(BaseNode):
module_name = 'iou'
"""
IOU VM implementation.
:param name: IOU VM name
:param vm_id: IOU VM identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Manager instance
:param console: TCP console port
"""
def __init__(self, name, vm_id, project, manager, console=None):
def __init__(self, name, node_id, project, manager, console=None):
super().__init__(name, vm_id, project, manager, console=console)
super().__init__(name, node_id, project, manager, console=console)
self._iouyap_process = None
self._iou_process = None
@@ -202,7 +202,7 @@ class IOUVM(BaseVM):
def __json__(self):
iou_vm_info = {"name": self.name,
"vm_id": self.id,
"node_id": self.id,
"vm_directory": self.working_dir,
"console": self._console,
"project_id": self.project.id,
@@ -315,7 +315,7 @@ class IOUVM(BaseVM):
new_nvram=nvram))
self._nvram = nvram
@BaseVM.name.setter
@BaseNode.name.setter
def name(self, new_name):
"""
Sets the name of this IOU VM.
@@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class VMError(Exception):
class NodeError(Exception):
def __init__(self, message, original_exception=None):
+40 -40
View File
@@ -24,7 +24,7 @@ import zipstream
import zipfile
import json
from uuid import UUID, uuid4
from uuid import UUID
from .port_manager import PortManager
from .notification_manager import NotificationManager
from ..config import Config
@@ -38,8 +38,8 @@ log = logging.getLogger(__name__)
class Project:
"""
A project contains a list of VM.
In theory VM are isolated project/project.
A project contains a list of nodes.
In theory nodes are isolated project/project.
:param project_id: force project identifier (None by default auto generate an UUID)
:param path: path of the project. (None use the standard directory)
@@ -55,8 +55,8 @@ class Project:
raise aiohttp.web.HTTPBadRequest(text="{} is not a valid UUID".format(project_id))
self._id = project_id
self._vms = set()
self._vms_to_destroy = set()
self._nodes = set()
self._nodes_to_destroy = set()
self.temporary = temporary
self._used_tcp_ports = set()
self._used_udp_ports = set()
@@ -155,9 +155,9 @@ class Project:
self._name = name
@property
def vms(self):
def nodes(self):
return self._vms
return self._nodes
@property
def temporary(self):
@@ -260,21 +260,21 @@ class Project:
return os.path.join(self._path, "project-files", module_name)
def vm_working_directory(self, vm):
def node_working_directory(self, node):
"""
Returns a working directory for a specific VM.
Returns a working directory for a specific node.
If the directory doesn't exist, the directory is created.
:param vm: VM instance
:param node: Node instance
:returns: VM working directory
:returns: Node working directory
"""
workdir = os.path.join(self._path, "project-files", vm.manager.module_name.lower(), vm.id)
workdir = os.path.join(self._path, "project-files", node.manager.module_name.lower(), node.id)
try:
os.makedirs(workdir, exist_ok=True)
except OSError as e:
raise aiohttp.web.HTTPInternalServerError(text="Could not create the VM working directory: {}".format(e))
raise aiohttp.web.HTTPInternalServerError(text="Could not create the node working directory: {}".format(e))
return workdir
def tmp_working_directory(self):
@@ -297,34 +297,34 @@ class Project:
raise aiohttp.web.HTTPInternalServerError(text="Could not create the capture working directory: {}".format(e))
return workdir
def mark_vm_for_destruction(self, vm):
def mark_node_for_destruction(self, node):
"""
:param vm: An instance of VM
:param node: An instance of Node
"""
self.remove_vm(vm)
self._vms_to_destroy.add(vm)
self.remove_node(node)
self._nodes_to_destroy.add(node)
def add_vm(self, vm):
def add_node(self, node):
"""
Adds a VM to the project.
In theory this should be called by the VM manager.
Adds a node to the project.
In theory this should be called by the node manager.
:param vm: VM instance
:param node: Node instance
"""
self._vms.add(vm)
self._nodes.add(node)
def remove_vm(self, vm):
def remove_node(self, node):
"""
Removes a VM from the project.
In theory this should be called by the VM manager.
Removes a node from the project.
In theory this should be called by the node manager.
:param vm: VM instance
:param node: Node instance
"""
if vm in self._vms:
self._vms.remove(vm)
if node in self._nodes:
self._nodes.remove(node)
@asyncio.coroutine
def close(self):
@@ -353,8 +353,8 @@ class Project:
"""
tasks = []
for vm in self._vms:
tasks.append(asyncio.async(vm.manager.close_vm(vm.id)))
for node in self._nodes:
tasks.append(asyncio.async(node.manager.close_node(node.id)))
if tasks:
done, _ = yield from asyncio.wait(tasks)
@@ -362,7 +362,7 @@ class Project:
try:
future.result()
except (Exception, GeneratorExit) as e:
log.error("Could not close VM or device {}".format(e), exc_info=1)
log.error("Could not close node {}".format(e), exc_info=1)
if cleanup and os.path.exists(self.path):
try:
@@ -378,7 +378,7 @@ class Project:
if self._used_udp_ports:
log.warning("Project {} has UDP ports still in use: {}".format(self.id, self._used_udp_ports))
# clean the remaining ports that have not been cleaned by their respective VM or device.
# clean the remaining ports that have not been cleaned by their respective node.
port_manager = PortManager.instance()
for port in self._used_tcp_ports.copy():
port_manager.release_tcp_port(port, self)
@@ -391,10 +391,10 @@ class Project:
Writes project changes on disk
"""
while self._vms_to_destroy:
vm = self._vms_to_destroy.pop()
yield from vm.delete()
self.remove_vm(vm)
while self._nodes_to_destroy:
node = self._nodes_to_destroy.pop()
yield from node.delete()
self.remove_node(node)
for module in self.compute():
yield from module.instance().project_committed(self)
@@ -427,7 +427,7 @@ class Project:
def compute(self):
"""
Returns all loaded VM compute.
Returns all loaded modules from compute.
"""
# We import it at the last time to avoid circular dependencies
@@ -571,7 +571,7 @@ class Project:
Import a project contain in a zip file
:param stream: A io.BytesIO of the zipfile
:param gns3vm: True move docker, iou and qemu to the GNS3 VM
:param gns3vm: True move Docker, IOU and Qemu to the GNS3 VM
"""
with zipfile.ZipFile(stream) as myzip:
@@ -608,7 +608,7 @@ class Project:
vm_directory = os.path.join(self.path, "servers", "vm", "project-files")
vm_server_use = False
for module, device_type in modules_to_vm.items():
for module, vm_type in modules_to_vm.items():
module_directory = os.path.join(self.path, "project-files", module)
if os.path.exists(module_directory):
os.makedirs(vm_directory, exist_ok=True)
@@ -616,7 +616,7 @@ class Project:
# Patch node to use the GNS3 VM
for node in topology["topology"]["nodes"]:
if node["type"] == device_type:
if node["type"] == vm_type:
node["server_id"] = 2
vm_server_use = True
+4 -4
View File
@@ -94,7 +94,7 @@ class ProjectManager:
raise aiohttp.web.HTTPNotFound(text="Project ID {} doesn't exist".format(project_id))
del self._projects[project_id]
def check_hardware_virtualization(self, source_vm):
def check_hardware_virtualization(self, source_node):
"""
Checks if hardware virtualization can be used.
@@ -102,9 +102,9 @@ class ProjectManager:
"""
for project in self._projects.values():
for vm in project.vms:
if vm == source_vm:
for node in project.nodes:
if node == source_node:
continue
if vm.hw_virtualization and vm.__class__.__name__ != source_vm.__class__.__name__:
if node.hw_virtualization and node.__class__.__name__ != source_node.__class__.__name__:
return False
return True
+3 -3
View File
@@ -37,7 +37,7 @@ log = logging.getLogger(__name__)
class Qemu(BaseManager):
_VM_CLASS = QemuVM
_NODE_CLASS = QemuVM
@staticmethod
@asyncio.coroutine
@@ -218,10 +218,10 @@ class Qemu(BaseManager):
@staticmethod
def get_legacy_vm_workdir(legacy_vm_id, name):
"""
Returns the name of the legacy working directory name for a VM.
Returns the name of the legacy working directory name for a node.
:param legacy_vm_id: legacy VM identifier (integer)
:param: VM name (not used)
:param: node name (not used)
:returns: working directory name
"""
+2 -2
View File
@@ -19,9 +19,9 @@
Custom exceptions for the Qemu module.
"""
from ..vm_error import VMError
from ..node_error import NodeError
class QemuError(VMError):
class QemuError(NodeError):
pass
+6 -6
View File
@@ -36,7 +36,7 @@ from ..adapters.ethernet_adapter import EthernetAdapter
from ..nios.nio_udp import NIOUDP
from ..nios.nio_tap import NIOTAP
from ..nios.nio_nat import NIONAT
from ..base_vm import BaseVM
from ..base_node import BaseNode
from ...schemas.qemu import QEMU_OBJECT_SCHEMA, QEMU_PLATFORMS
from ...utils.asyncio import monitor_process
from ...utils.images import md5sum
@@ -48,14 +48,14 @@ import logging
log = logging.getLogger(__name__)
class QemuVM(BaseVM):
class QemuVM(BaseNode):
module_name = 'qemu'
"""
QEMU VM implementation.
:param name: Qemu VM name
:param vm_id: Qemu VM identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Manager instance
:param console: TCP console port
@@ -64,9 +64,9 @@ class QemuVM(BaseVM):
:param console: TCP console port
"""
def __init__(self, name, vm_id, project, manager, linked_clone=True, qemu_path=None, console=None, console_type="telnet", platform=None):
def __init__(self, name, node_id, project, manager, linked_clone=True, qemu_path=None, console=None, console_type="telnet", platform=None):
super().__init__(name, vm_id, project, manager, console=console, console_type=console_type)
super().__init__(name, node_id, project, manager, console=console, console_type=console_type)
server_config = manager.config.get_section_config("Server")
self._host = server_config.get("host", "127.0.0.1")
self._monitor_host = server_config.get("monitor_host", "127.0.0.1")
@@ -1448,7 +1448,7 @@ class QemuVM(BaseVM):
def __json__(self):
answer = {
"project_id": self.project.id,
"vm_id": self.id,
"node_id": self.id,
"vm_directory": self.working_dir
}
# Qemu has a long list of options. The JSON schema is the single source of information
+7 -7
View File
@@ -35,7 +35,7 @@ from .virtualbox_error import VirtualBoxError
class VirtualBox(BaseManager):
_VM_CLASS = VirtualBoxVM
_NODE_CLASS = VirtualBoxVM
def __init__(self):
@@ -160,7 +160,7 @@ class VirtualBox(BaseManager):
Gets VirtualBox VM list.
"""
vms = []
vbox_vms = []
result = yield from self.execute("list", ["vms"])
for line in result:
if len(line) == 0 or line[0] != '"' or line[-1:] != "}":
@@ -182,16 +182,16 @@ class VirtualBox(BaseManager):
break
except ValueError:
continue
vms.append({"vmname": vmname, "ram": ram})
return vms
vbox_vms.append({"vmname": vmname, "ram": ram})
return vbox_vms
@staticmethod
def get_legacy_vm_workdir(legacy_vm_id, name):
"""
Returns the name of the legacy working directory name for a VM.
Returns the name of the legacy working directory name for a node.
:param legacy_vm_id: legacy VM identifier (not used)
:param name: VM name
:param legacy_vm_id: legacy node identifier (not used)
:param name: node name
:returns: working directory name
"""
@@ -19,9 +19,9 @@
Custom exceptions for the VirtualBox module.
"""
from ..vm_error import VMError
from ..node_error import NodeError
class VirtualBoxError(VMError):
class VirtualBoxError(NodeError):
pass
@@ -35,7 +35,7 @@ from .virtualbox_error import VirtualBoxError
from ..nios.nio_udp import NIOUDP
from ..nios.nio_nat import NIONAT
from ..adapters.ethernet_adapter import EthernetAdapter
from ..base_vm import BaseVM
from ..base_node import BaseNode
if sys.platform.startswith('win'):
import msvcrt
@@ -45,15 +45,15 @@ import logging
log = logging.getLogger(__name__)
class VirtualBoxVM(BaseVM):
class VirtualBoxVM(BaseNode):
"""
VirtualBox VM implementation.
"""
def __init__(self, name, vm_id, project, manager, vmname, linked_clone, console=None, adapters=0):
def __init__(self, name, node_id, project, manager, vmname, linked_clone, console=None, adapters=0):
super().__init__(name, vm_id, project, manager, console=console)
super().__init__(name, node_id, project, manager, console=console)
self._maximum_adapters = 8
self._linked_clone = linked_clone
@@ -75,7 +75,7 @@ class VirtualBoxVM(BaseVM):
def __json__(self):
json = {"name": self.name,
"vm_id": self.id,
"node_id": self.id,
"console": self.console,
"project_id": self.project.id,
"vmname": self.vmname,
+14 -14
View File
@@ -43,7 +43,7 @@ from gns3server.compute.vmware.nio_vmnet import NIOVMNET
class VMware(BaseManager):
_VM_CLASS = VMwareVM
_NODE_CLASS = VMwareVM
def __init__(self):
@@ -324,8 +324,8 @@ class VMware(BaseManager):
vmnet_interfaces = self._get_vmnet_interfaces()
# remove vmnets already in use
for vm in self._vms.values():
for used_vmnet in vm.vmnets:
for vmware_vm in self._nodes.values():
for used_vmnet in vmware_vm.vmnets:
if used_vmnet in vmnet_interfaces:
log.debug("{} is already in use".format(used_vmnet))
vmnet_interfaces.remove(used_vmnet)
@@ -558,7 +558,7 @@ class VMware(BaseManager):
"""
vm_entries = {}
vms = []
vmware_vms = []
try:
log.debug('Reading VMware inventory file "{}"'.format(inventory_path))
pairs = self.parse_vmware_file(inventory_path)
@@ -577,8 +577,8 @@ class VMware(BaseManager):
for vm_settings in vm_entries.values():
if "displayname" in vm_settings and "config" in vm_settings:
log.debug('Found VM named "{}" with VMX file "{}"'.format(vm_settings["displayname"], vm_settings["config"]))
vms.append({"vmname": vm_settings["displayname"], "vmx_path": vm_settings["config"]})
return vms
vmware_vms.append({"vmname": vm_settings["displayname"], "vmx_path": vm_settings["config"]})
return vmware_vms
def _get_vms_from_directory(self, directory):
"""
@@ -589,7 +589,7 @@ class VMware(BaseManager):
:returns: list of VMs
"""
vms = []
vmware_vms = []
for path, _, filenames in os.walk(directory):
for filename in filenames:
if os.path.splitext(filename)[1] == ".vmx":
@@ -599,11 +599,11 @@ class VMware(BaseManager):
pairs = self.parse_vmware_file(vmx_path)
if "displayname" in pairs:
log.debug('Found VM named "{}"'.format(pairs["displayname"]))
vms.append({"vmname": pairs["displayname"], "vmx_path": vmx_path})
vmware_vms.append({"vmname": pairs["displayname"], "vmx_path": vmx_path})
except OSError as e:
log.warning('Could not read VMware VMX file "{}": {}'.format(vmx_path, e))
continue
return vms
return vmware_vms
@staticmethod
def get_vmware_inventory_path():
@@ -687,7 +687,7 @@ class VMware(BaseManager):
default_vm_path = pairs["prefvmx.defaultvmpath"]
if not os.path.isdir(default_vm_path):
raise VMwareError('Could not find the default VM directory: "{}"'.format(default_vm_path))
vms = self._get_vms_from_directory(default_vm_path)
vmware_vms = self._get_vms_from_directory(default_vm_path)
# looks for VMX paths in the preferences file in case not all VMs are in the default directory
for key, value in pairs.items():
@@ -696,12 +696,12 @@ class VMware(BaseManager):
display_name = "pref.mruVM{}.displayName".format(m.group(1))
if display_name in pairs:
found = False
for vm in vms:
if vm["vmname"] == display_name:
for vmware_vm in vmware_vms:
if vmware_vm["vmname"] == display_name:
found = True
if found is False:
vms.append({"vmname": pairs[display_name], "vmx_path": value})
return vms
vmware_vms.append({"vmname": pairs[display_name], "vmx_path": value})
return vmware_vms
@staticmethod
def _get_linux_vmware_binary():
+2 -2
View File
@@ -19,9 +19,9 @@
Custom exceptions for the VMware module.
"""
from ..vm_error import VMError
from ..node_error import NodeError
class VMwareError(VMError):
class VMwareError(NodeError):
pass
+6 -6
View File
@@ -34,7 +34,7 @@ from ..nios.nio_udp import NIOUDP
from ..nios.nio_nat import NIONAT
from .nio_vmnet import NIOVMNET
from ..adapters.ethernet_adapter import EthernetAdapter
from ..base_vm import BaseVM
from ..base_node import BaseNode
if sys.platform.startswith('win'):
import msvcrt
@@ -44,15 +44,15 @@ import logging
log = logging.getLogger(__name__)
class VMwareVM(BaseVM):
class VMwareVM(BaseNode):
"""
VMware VM implementation.
"""
def __init__(self, name, vm_id, project, manager, vmx_path, linked_clone, console=None):
def __init__(self, name, node_id, project, manager, vmx_path, linked_clone, console=None):
super().__init__(name, vm_id, project, manager, console=console)
super().__init__(name, node_id, project, manager, console=console)
self._linked_clone = linked_clone
self._vmx_pairs = OrderedDict()
@@ -75,12 +75,12 @@ class VMwareVM(BaseVM):
self._use_any_adapter = False
if not os.path.exists(vmx_path):
raise VMwareError('VMware VM "{name}" [{id}]: could not find VMX file "{vmx_path}"'.format(name=name, id=vm_id, vmx_path=vmx_path))
raise VMwareError('VMware VM "{name}" [{id}]: could not find VMX file "{vmx_path}"'.format(name=name, id=node_id, vmx_path=vmx_path))
def __json__(self):
json = {"name": self.name,
"vm_id": self.id,
"node_id": self.id,
"console": self.console,
"project_id": self.project.id,
"vmx_path": self.vmx_path,
+20 -20
View File
@@ -29,7 +29,7 @@ from .vpcs_vm import VPCSVM
class VPCS(BaseManager):
_VM_CLASS = VPCSVM
_NODE_CLASS = VPCSVM
def __init__(self):
@@ -38,55 +38,55 @@ class VPCS(BaseManager):
self._used_mac_ids = {}
@asyncio.coroutine
def create_vm(self, *args, **kwargs):
def create_node(self, *args, **kwargs):
"""
Creates a new VPCS VM.
:returns: VPCSVM instance
"""
vm = yield from super().create_vm(*args, **kwargs)
self._free_mac_ids.setdefault(vm.project.id, list(range(0, 255)))
node = yield from super().create_node(*args, **kwargs)
self._free_mac_ids.setdefault(node.project.id, list(range(0, 255)))
try:
self._used_mac_ids[vm.id] = self._free_mac_ids[vm.project.id].pop(0)
self._used_mac_ids[node.id] = self._free_mac_ids[node.project.id].pop(0)
except IndexError:
raise VPCSError("Cannot create a new VPCS VM (limit of 255 VMs reached on this host)")
return vm
return node
@asyncio.coroutine
def close_vm(self, vm_id, *args, **kwargs):
def close_node(self, node_id, *args, **kwargs):
"""
Closes a VPCS VM.
:returns: VPCSVM instance
"""
vm = self.get_vm(vm_id)
if vm_id in self._used_mac_ids:
i = self._used_mac_ids[vm_id]
self._free_mac_ids[vm.project.id].insert(0, i)
del self._used_mac_ids[vm_id]
yield from super().close_vm(vm_id, *args, **kwargs)
return vm
node = self.get_node(node_id)
if node_id in self._used_mac_ids:
i = self._used_mac_ids[node_id]
self._free_mac_ids[node.project.id].insert(0, i)
del self._used_mac_ids[node_id]
yield from super().close_node(node_id, *args, **kwargs)
return node
def get_mac_id(self, vm_id):
def get_mac_id(self, node_id):
"""
Get an unique VPCS MAC id (offset)
:param vm_id: VPCS VM identifier
:param node_id: VPCS node identifier
:returns: VPCS MAC identifier
"""
return self._used_mac_ids.get(vm_id, 1)
return self._used_mac_ids.get(node_id, 1)
@staticmethod
def get_legacy_vm_workdir(legacy_vm_id, name):
"""
Returns the name of the legacy working directory name for a VM.
Returns the name of the legacy working directory name for a node.
:param legacy_vm_id: legacy VM identifier (integer)
:param name: VM name (not used)
:param legacy_vm_id: legacy node identifier (integer)
:param name: node name (not used)
:returns: working directory name
"""
+2 -2
View File
@@ -19,9 +19,9 @@
Custom exceptions for the VPCS module.
"""
from ..vm_error import VMError
from ..node_error import NodeError
class VPCSError(VMError):
class VPCSError(NodeError):
pass
+7 -7
View File
@@ -36,29 +36,29 @@ from .vpcs_error import VPCSError
from ..adapters.ethernet_adapter import EthernetAdapter
from ..nios.nio_udp import NIOUDP
from ..nios.nio_tap import NIOTAP
from ..base_vm import BaseVM
from ..base_node import BaseNode
import logging
log = logging.getLogger(__name__)
class VPCSVM(BaseVM):
class VPCSVM(BaseNode):
module_name = 'vpcs'
"""
VPCS VM implementation.
:param name: VPCS VM name
:param vm_id: VPCS VM identifier
:param node_id: Node identifier
:param project: Project instance
:param manager: Manager instance
:param console: TCP console port
:param startup_script: content of the startup script file
"""
def __init__(self, name, vm_id, project, manager, console=None, startup_script=None):
def __init__(self, name, node_id, project, manager, console=None, startup_script=None):
super().__init__(name, vm_id, project, manager, console=console)
super().__init__(name, node_id, project, manager, console=console)
self._process = None
self._vpcs_stdout_file = ""
self._vpcs_version = None
@@ -108,7 +108,7 @@ class VPCSVM(BaseVM):
def __json__(self):
return {"name": self.name,
"vm_id": self.id,
"node_id": self.id,
"vm_directory": self.working_dir,
"status": self.status,
"console": self._console,
@@ -145,7 +145,7 @@ class VPCSVM(BaseVM):
path = shutil.which("vpcs")
return path
@BaseVM.name.setter
@BaseNode.name.setter
def name(self, new_name):
"""
Sets the name of this VPCS VM.