Basic VMware support (start & stop a VM).

This commit is contained in:
Jeremy committed 2015-04-30 19:05:37 -06:00
1 parent f8f6f5dc5d
commit ab60d7929b
8 files changed
+701 -2

No files matched your search

+106
View File
@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
VMware player/workstation server module.
"""
import os
import sys
import shutil
import asyncio
import subprocess
import logging
log = logging.getLogger(__name__)
from ..base_manager import BaseManager
from .vmware_vm import VMwareVM
from .vmware_error import VMwareError
class VMware(BaseManager):
_VM_CLASS = VMwareVM
def __init__(self):
super().__init__()
self._vmrun_path = None
self._host_type = "player"
@property
def vmrun_path(self):
"""
Returns the path vmrun utility.
:returns: path
"""
return self._vmrun_path
def find_vmrun(self):
# look for vmrun
vmrun_path = self.config.get_section_config("VMware").get("vmrun_path")
if not vmrun_path:
if sys.platform.startswith("win"):
pass # TODO: use registry to find vmrun
elif sys.platform.startswith("darwin"):
vmrun_path = "/Applications/VMware Fusion.app/Contents/Library/vmrun"
else:
vmrun_path = shutil.which("vmrun")
if not vmrun_path:
raise VMwareError("Could not find vmrun")
if not os.path.isfile(vmrun_path):
raise VMwareError("vmrun {} is not accessible".format(vmrun_path))
if not os.access(vmrun_path, os.X_OK):
raise VMwareError("vmrun is not executable")
if os.path.basename(vmrun_path) not in ["vmrun", "vmrun.exe"]:
raise VMwareError("Invalid vmrun executable name {}".format(os.path.basename(vmrun_path)))
self._vmrun_path = vmrun_path
return vmrun_path
@asyncio.coroutine
def execute(self, subcommand, args, timeout=60, host_type=None):
vmrun_path = self.vmrun_path
if not vmrun_path:
vmrun_path = self.find_vmrun()
if host_type is None:
host_type = self._host_type
command = [vmrun_path, "-T", host_type, subcommand]
command.extend(args)
log.debug("Executing vmrun with command: {}".format(command))
try:
process = yield from asyncio.create_subprocess_exec(*command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
except (OSError, subprocess.SubprocessError) as e:
raise VMwareError("Could not execute vmrun: {}".format(e))
try:
stdout_data, _ = yield from asyncio.wait_for(process.communicate(), timeout=timeout)
except asyncio.TimeoutError:
raise VMwareError("vmrun has timed out after {} seconds!".format(timeout))
if process.returncode:
# vmrun print errors on stdout
vmrun_error = stdout_data.decode("utf-8", errors="ignore")
raise VMwareError("vmrun has returned an error: {}".format(vmrun_error))
return stdout_data.decode("utf-8", errors="ignore").splitlines()
+27
View File
@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Custom exceptions for the VirtualBox module.
"""
from ..vm_error import VMError
class VMwareError(VMError):
pass
+192
View File
@@ -0,0 +1,192 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
VMware VM instance.
"""
import sys
import shlex
import re
import os
import tempfile
import json
import socket
import asyncio
from pkg_resources import parse_version
from .vmware_error import VMwareError
from ..nios.nio_udp import NIOUDP
from ..base_vm import BaseVM
import logging
log = logging.getLogger(__name__)
class VMwareVM(BaseVM):
"""
VMware VM implementation.
"""
def __init__(self, name, vm_id, project, manager, vmx_path, linked_clone, console=None):
super().__init__(name, vm_id, project, manager, console=console)
self._linked_clone = linked_clone
self._closed = False
# VMware VM settings
self._headless = False
self._vmx_path = vmx_path
def __json__(self):
return {"name": self.name,
"vm_id": self.id,
"console": self.console,
"project_id": self.project.id,
"vmx_path": self.vmx_path,
"headless": self.headless}
@asyncio.coroutine
def _control_vm(self, subcommand, *additional_args):
args = [self._vmx_path]
args.extend(additional_args)
result = yield from self.manager.execute(subcommand, args)
log.debug("Control VM '{}' result: {}".format(subcommand, result))
return result
@asyncio.coroutine
def start(self):
"""
Starts this VMware VM.
"""
if self._headless:
yield from self._control_vm("start", "nogui")
else:
yield from self._control_vm("start")
log.info("VMware VM '{name}' [{id}] started".format(name=self.name, id=self.id))
@asyncio.coroutine
def stop(self):
"""
Stops this VMware VM.
"""
yield from self._control_vm("stop")
log.info("VMware VM '{name}' [{id}] stopped".format(name=self.name, id=self.id))
@asyncio.coroutine
def suspend(self):
"""
Suspends this VMware VM.
"""
yield from self._control_vm("suspend")
log.info("VMware VM '{name}' [{id}] stopped".format(name=self.name, id=self.id))
@asyncio.coroutine
def resume(self):
"""
Resumes this VMware VM.
"""
yield from self.start()
log.info("VMware VM '{name}' [{id}] resumed".format(name=self.name, id=self.id))
@asyncio.coroutine
def reload(self):
"""
Reloads this VMware VM.
"""
yield from self._control_vm("reset")
log.info("VMware VM '{name}' [{id}] reloaded".format(name=self.name, id=self.id))
@asyncio.coroutine
def close(self):
"""
Closes this VirtualBox VM.
"""
if self._closed:
# VM is already closed
return
log.debug("VMware VM '{name}' [{id}] is closing".format(name=self.name, id=self.id))
if self._console:
self._manager.port_manager.release_tcp_port(self._console, self._project)
self._console = None
#for adapter in self._ethernet_adapters.values():
# if adapter is not None:
# for nio in adapter.ports.values():
# if nio and isinstance(nio, NIOUDP):
# self.manager.port_manager.release_udp_port(nio.lport, self._project)
yield from self.stop()
log.info("VirtualBox VM '{name}' [{id}] closed".format(name=self.name, id=self.id))
self._closed = True
@property
def headless(self):
"""
Returns either the VM will start in headless mode
:returns: boolean
"""
return self._headless
@headless.setter
def headless(self, headless):
"""
Sets either the VM will start in headless mode
:param headless: boolean
"""
if headless:
log.info("VMware VM '{name}' [{id}] has enabled the headless mode".format(name=self.name, id=self.id))
else:
log.info("VMware VM '{name}' [{id}] has disabled the headless mode".format(name=self.name, id=self.id))
self._headless = headless
@property
def vmx_path(self):
"""
Returns the path to the vmx file.
:returns: VMware vmx file
"""
return self._vmx_path
@vmx_path.setter
def vmx_path(self, vmx_path):
"""
Sets the path to the vmx file.
:param vmx_path: VMware vmx file
"""
log.info("VMware VM '{name}' [{id}] has set the vmx file path to '{vmx}'".format(name=self.name, id=self.id, vmx=vmx_path))
self._vmx_path = vmx_path