From cb7b9e8190253f0b49a2091d8bb29e31c9660480 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Fri, 15 May 2015 19:09:48 -0600 Subject: [PATCH] Adapters for VMware VMs. --- gns3server/handlers/api/vmware_handler.py | 52 ++++++++++++++++++++++ gns3server/modules/vmware/__init__.py | 23 ++++++++-- gns3server/modules/vmware/vmware_vm.py | 54 ++++++++++++++++++++++- gns3server/utils/interfaces.py | 3 +- 4 files changed, 125 insertions(+), 7 deletions(-) diff --git a/gns3server/handlers/api/vmware_handler.py b/gns3server/handlers/api/vmware_handler.py index 65b39316..c574b070 100644 --- a/gns3server/handlers/api/vmware_handler.py +++ b/gns3server/handlers/api/vmware_handler.py @@ -15,10 +15,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from aiohttp.web import HTTPConflict from ...web.route import Route from ...schemas.vmware import VMWARE_CREATE_SCHEMA from ...schemas.vmware import VMWARE_UPDATE_SCHEMA from ...schemas.vmware import VMWARE_OBJECT_SCHEMA +from ...schemas.nio import NIO_SCHEMA from ...modules.vmware import VMware from ...modules.project_manager import ProjectManager @@ -240,3 +242,53 @@ class VMwareHandler: vm = vmware_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) yield from vm.reload() response.set_status(204) + + @Route.post( + r"/projects/{project_id}/vmware/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", + parameters={ + "project_id": "UUID for the project", + "vm_id": "UUID for the instance", + "adapter_number": "Adapter where the nio should be added", + "port_number": "Port on the adapter (always 0)" + }, + status_codes={ + 201: "NIO created", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Add a NIO to a VMware VM instance", + input=NIO_SCHEMA, + output=NIO_SCHEMA) + def create_nio(request, response): + + vmware_manager = VMware.instance() + vm = vmware_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) + nio_type = request.json["type"] + if nio_type != "nio_udp": + raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type)) + nio = vmware_manager.create_nio(None, request.json) + vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio) + response.set_status(201) + response.json(nio) + + @classmethod + @Route.delete( + r"/projects/{project_id}/vmware/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", + parameters={ + "project_id": "UUID for the project", + "vm_id": "UUID for the instance", + "adapter_number": "Adapter from where the nio should be removed", + "port_number": "Port on the adapter (always 0)" + }, + status_codes={ + 204: "NIO deleted", + 400: "Invalid request", + 404: "Instance doesn't exist" + }, + description="Remove a NIO from a VMware VM instance") + def delete_nio(request, response): + + vmware_manager = VMware.instance() + vm = vmware_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) + vm.adapter_remove_nio_binding(int(request.match_info["adapter_number"])) + response.set_status(204) diff --git a/gns3server/modules/vmware/__init__.py b/gns3server/modules/vmware/__init__.py index e02f20b2..e0a5fe44 100644 --- a/gns3server/modules/vmware/__init__.py +++ b/gns3server/modules/vmware/__init__.py @@ -81,6 +81,23 @@ class VMware(BaseManager): self._vmrun_path = vmrun_path return vmrun_path + @property + def host_type(self): + """ + Returns the VMware host type. + player = VMware player + ws = VMware Workstation + fusion = VMware Fusion + + :returns: host type (string) + """ + + if sys.platform.startswith("darwin"): + host_type = "fusion" + else: + host_type = self.config.get_section_config("VMware").get("host_type", "ws") + return host_type + @asyncio.coroutine def execute(self, subcommand, args, timeout=60, host_type=None): @@ -88,10 +105,8 @@ class VMware(BaseManager): if not vmrun_path: vmrun_path = self.find_vmrun() if host_type is None: - if sys.platform.startswith("darwin"): - host_type = "fusion" - else: - host_type = self.config.get_section_config("VMware").get("host_type", "ws") + host_type = self.host_type + command = [vmrun_path, "-T", host_type, subcommand] command.extend(args) log.debug("Executing vmrun with command: {}".format(command)) diff --git a/gns3server/modules/vmware/vmware_vm.py b/gns3server/modules/vmware/vmware_vm.py index 5918e590..b84bb546 100644 --- a/gns3server/modules/vmware/vmware_vm.py +++ b/gns3server/modules/vmware/vmware_vm.py @@ -145,6 +145,8 @@ class VMwareVM(BaseVM): Suspends this VMware VM. """ + if self.manager.host_type != "ws": + raise VMwareError("Pausing a VM is only supported by VMware Workstation") yield from self._control_vm("pause") log.info("VMware VM '{name}' [{id}] paused".format(name=self.name, id=self.id)) @@ -154,6 +156,8 @@ class VMwareVM(BaseVM): Resumes this VMware VM. """ + if self.manager.host_type != "ws": + raise VMwareError("Unpausing a VM is only supported by VMware Workstation") yield from self._control_vm("unpause") log.info("VMware VM '{name}' [{id}] resumed".format(name=self.name, id=self.id)) @@ -250,8 +254,8 @@ class VMwareVM(BaseVM): return self._enable_remote_console - @asyncio.coroutine - def set_enable_remote_console(self, enable_remote_console): + @enable_remote_console.setter + def enable_remote_console(self, enable_remote_console): """ Sets either the console is enabled or not @@ -319,3 +323,49 @@ class VMwareVM(BaseVM): log.info("VMware VM '{name}' [{id}]: adapter type changed to {adapter_type}".format(name=self.name, id=self.id, adapter_type=adapter_type)) + + def adapter_add_nio_binding(self, adapter_number, nio): + """ + Adds an adapter NIO binding. + + :param adapter_number: adapter number + :param nio: NIO instance to add to the slot/port + """ + + try: + adapter = self._ethernet_adapters[adapter_number] + except IndexError: + raise VMwareError("Adapter {adapter_number} doesn't exist on VMware VM '{name}'".format(name=self.name, + adapter_number=adapter_number)) + + adapter.add_nio(0, nio) + log.info("VMware VM '{name}' [{id}]: {nio} added to adapter {adapter_number}".format(name=self.name, + id=self.id, + nio=nio, + adapter_number=adapter_number)) + + def adapter_remove_nio_binding(self, adapter_number): + """ + Removes an adapter NIO binding. + + :param adapter_number: adapter number + + :returns: NIO instance + """ + + try: + adapter = self._ethernet_adapters[adapter_number] + except IndexError: + raise VMwareError("Adapter {adapter_number} doesn't exist on VMware VM '{name}'".format(name=self.name, + adapter_number=adapter_number)) + + nio = adapter.get_nio(0) + if isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport, self._project) + adapter.remove_nio(0) + + log.info("VMware VM '{name}' [{id}]: {nio} removed from adapter {adapter_number}".format(name=self.name, + id=self.id, + nio=nio, + adapter_number=adapter_number)) + return nio diff --git a/gns3server/utils/interfaces.py b/gns3server/utils/interfaces.py index 4123459d..c9a5df88 100644 --- a/gns3server/utils/interfaces.py +++ b/gns3server/utils/interfaces.py @@ -69,7 +69,8 @@ def get_windows_interfaces(): # adapter is connected or media disconnected npf_interface = "\\Device\\NPF_{guid}".format(guid=adapter.GUID) interfaces.append({"id": npf_interface, - "name": adapter.NetConnectionID}) + "name": adapter.NetConnectionID, + "netcard": adapter.name}) except (AttributeError, pywintypes.com_error): log.warn("Could not use the COM service to retrieve interface info, trying using the registry...") return _get_windows_interfaces_from_registry()