diff --git a/gns3server/controller/gns3vm/__init__.py b/gns3server/controller/gns3vm/__init__.py index b6f9636b..1451adc4 100644 --- a/gns3server/controller/gns3vm/__init__.py +++ b/gns3server/controller/gns3vm/__init__.py @@ -21,6 +21,7 @@ import asyncio from .vmware_gns3_vm import VMwareGNS3VM from .virtualbox_gns3_vm import VirtualBoxGNS3VM +from .remote_gns3_vm import RemoteGNS3VM import logging log = logging.getLogger(__name__) @@ -48,22 +49,37 @@ class GNS3VM: """ :returns: Return list of engines supported by GNS3 for the GNS3VM """ - virtualbox_informations = { - "engine_id": "virtualbox", - "name": "VirtualBox", - "description": "VirtualBox doesn't support nested virtualization, this means running Qemu based VM could be very slow." - } vmware_informations = { "engine_id": "vmware", - "description": "VMware is the recommended choice for best performances." + "description": "VMware is the recommended choice for best performances.", + "support_auto_stop": True, + "support_headless": True } if sys.platform.startswith("darwin"): vmware_informations["name"] = "VMware Fusion" else: vmware_informations["name"] = "VMware Workstation / Player" + + virtualbox_informations = { + "engine_id": "virtualbox", + "name": "VirtualBox", + "description": "VirtualBox doesn't support nested virtualization, this means running Qemu based VM could be very slow.", + "support_auto_stop": True, + "support_headless": True + } + + remote_informations = { + "engine_id": "remote", + "name": "Remote", + "description": "Use a remote GNS3 server as the GNS3 VM.", + "support_auto_stop": False, + "support_headless": False + } + return [ vmware_informations, - virtualbox_informations + virtualbox_informations, + remote_informations ] def _current_engine(self): @@ -166,11 +182,14 @@ class GNS3VM: return self._engines[engine] if engine == "vmware": - self._engines["vmware"] = VMwareGNS3VM() + self._engines["vmware"] = VMwareGNS3VM(self._controller) return self._engines["vmware"] elif engine == "virtualbox": - self._engines["virtualbox"] = VirtualBoxGNS3VM() + self._engines["virtualbox"] = VirtualBoxGNS3VM(self._controller) return self._engines["virtualbox"] + elif engine == "remote": + self._engines["remote"] = RemoteGNS3VM(self._controller) + return self._engines["remote"] raise NotImplementedError("The engine {} for the GNS3 VM is not supported".format(engine)) def __json__(self): @@ -211,7 +230,7 @@ class GNS3VM: engine.vmname = self._settings["vmname"] yield from engine.start() yield from self._controller.add_compute(compute_id="vm", - name="GNS3 VM", + name="GNS3 VM ({})".format(engine.vmname), protocol=self.protocol, host=self.ip_address, port=self.port, diff --git a/gns3server/controller/gns3vm/base_gns3_vm.py b/gns3server/controller/gns3vm/base_gns3_vm.py index b9f38c13..0f59e878 100644 --- a/gns3server/controller/gns3vm/base_gns3_vm.py +++ b/gns3server/controller/gns3vm/base_gns3_vm.py @@ -24,8 +24,9 @@ log = logging.getLogger(__name__) class BaseGNS3VM: - def __init__(self): + def __init__(self, controller): + self._controller = controller self._vmname = None self._auto_stop = False self._ip_address = None diff --git a/gns3server/controller/gns3vm/remote_gns3_vm.py b/gns3server/controller/gns3vm/remote_gns3_vm.py new file mode 100644 index 00000000..085c018d --- /dev/null +++ b/gns3server/controller/gns3vm/remote_gns3_vm.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 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 . + +import asyncio + +from .base_gns3_vm import BaseGNS3VM +from .gns3_vm_error import GNS3VMError + + +import logging +log = logging.getLogger(__name__) + + +class RemoteGNS3VM(BaseGNS3VM): + + def __init__(self, controller): + + self._engine = "remote" + super().__init__(controller) + + @asyncio.coroutine + def list(self): + """ + List all VMs + """ + + res = [] + + for compute in self._controller.computes.values(): + if compute.id not in ["local", "vm"]: + res.append({"vmname": compute.name}) + return res + + @asyncio.coroutine + def start(self): + """ + Starts the GNS3 VM. + """ + + vm_compute = None + for compute in self._controller.computes.values(): + if compute.name == self.vmname: + self.running = True + self.protocol = compute.protocol + self.ip_address = compute.host + self.port = compute.port + self.user = compute.user + self.password = compute.password + return + raise GNS3VMError("Can't start the GNS3 VM remote VM {} not found".format(self.vmname)) + + @asyncio.coroutine + def stop(self): + """ + Stops the GNS3 VM. + """ + self.running = False diff --git a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py index 15be9c85..d066c975 100644 --- a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py +++ b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py @@ -32,9 +32,9 @@ log = logging.getLogger(__name__) class VirtualBoxGNS3VM(BaseGNS3VM): - def __init__(self): + def __init__(self, controller): - super().__init__() + super().__init__(controller) self._engine = "virtualbox" self._virtualbox_manager = VirtualBox() diff --git a/gns3server/controller/gns3vm/vmware_gns3_vm.py b/gns3server/controller/gns3vm/vmware_gns3_vm.py index 8cc17da5..657ec79f 100644 --- a/gns3server/controller/gns3vm/vmware_gns3_vm.py +++ b/gns3server/controller/gns3vm/vmware_gns3_vm.py @@ -32,10 +32,10 @@ log = logging.getLogger(__name__) class VMwareGNS3VM(BaseGNS3VM): - def __init__(self): + def __init__(self, controller): self._engine = "vmware" - super().__init__() + super().__init__(controller) self._vmware_manager = VMware() self._vmx_path = None diff --git a/tests/controller/gns3vm/test_remote_gns3_vm.py b/tests/controller/gns3vm/test_remote_gns3_vm.py new file mode 100644 index 00000000..e34538ea --- /dev/null +++ b/tests/controller/gns3vm/test_remote_gns3_vm.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 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 . + +import pytest + +from gns3server.controller.gns3vm.remote_gns3_vm import RemoteGNS3VM +from gns3server.controller.gns3vm.gns3_vm_error import GNS3VMError + + +@pytest.fixture +def gns3vm(controller): + return RemoteGNS3VM(controller) + + +def test_list(async_run, gns3vm, controller): + async_run(controller.add_compute("r1", name="R1", host="r1.local", connect=False)) + res = async_run(gns3vm.list()) + assert res == [{"vmname": "R1"}] + + +def test_start(async_run, gns3vm, controller): + async_run(controller.add_compute("r1", name="R1", + protocol="https", + host="r1.local", + port=8484, + user="hello", + password="world", + connect=False)) + gns3vm.vmname = "R1" + res = async_run(gns3vm.start()) + assert gns3vm.running + assert gns3vm.protocol == "https" + assert gns3vm.ip_address == "r1.local" + assert gns3vm.port == 8484 + assert gns3vm.user == "hello" + assert gns3vm.password == "world" + + +def test_start_invalid_vm(async_run, gns3vm, controller): + async_run(controller.add_compute("r1", name="R1", + protocol="https", + host="r1.local", + port=8484, + user="hello", + password="world")) + gns3vm.vmname = "R2" + with pytest.raises(GNS3VMError): + res = async_run(gns3vm.start()) + assert not gns3vm.running