From fc8b4c32161f75f2295eebe02eb9ca64b84aa6ea Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Thu, 25 Aug 2016 11:49:06 +0200 Subject: [PATCH] Start GNS3 VM with the controller Ref https://github.com/GNS3/gns3-gui/issues/1254 --- gns3server/controller/__init__.py | 12 +++- gns3server/controller/gns3vm/__init__.py | 70 +++++++++++++++++++ gns3server/controller/gns3vm/base_gns3_vm.py | 64 ++++++++++++++++- .../controller/gns3vm/vmware_gns3_vm.py | 7 +- tests/controller/test_controller.py | 23 ++++++ 5 files changed, 170 insertions(+), 6 deletions(-) diff --git a/gns3server/controller/__init__.py b/gns3server/controller/__init__.py index de3cf17e..53bd864e 100644 --- a/gns3server/controller/__init__.py +++ b/gns3server/controller/__init__.py @@ -62,6 +62,7 @@ class Controller: @asyncio.coroutine def start(self): log.info("Start controller") + yield from self.load() server_config = Config.instance().get_section_config("Server") self._computes["local"] = Compute(compute_id="local", controller=self, @@ -70,7 +71,16 @@ class Controller: port=server_config.getint("port", 3080), user=server_config.get("user", ""), password=server_config.get("password", "")) - yield from self.load() + if self.gns3vm.enable: + yield from self.gns3vm.start() + self._computes["vm"] = Compute(compute_id="vm", + name="GNS3 VM", + controller=self, + protocol=self.gns3vm.protocol, + host=self.gns3vm.ip_address, + port=self.gns3vm.port, + user=self.gns3vm.user, + password=self.gns3vm.password) @asyncio.coroutine def stop(self): diff --git a/gns3server/controller/gns3vm/__init__.py b/gns3server/controller/gns3vm/__init__.py index 28dcb154..9aad7b3d 100644 --- a/gns3server/controller/gns3vm/__init__.py +++ b/gns3server/controller/gns3vm/__init__.py @@ -21,6 +21,9 @@ import asyncio from .vmware_gns3_vm import VMwareGNS3VM from .virtualbox_gns3_vm import VirtualBoxGNS3VM +import logging +log = logging.getLogger(__name__) + class GNS3VM: """ @@ -62,6 +65,61 @@ class GNS3VM: virtualbox_informations ] + def _current_engine(self): + return self._get_engine(self._settings["engine"]) + + @property + def ip_address(self): + """ + Returns the GNS3 VM IP address. + + :returns: VM IP address + """ + return self._current_engine().ip_address + + @property + def user(self): + """ + Returns the GNS3 VM user. + + :returns: VM user + """ + return self._current_engine().user + + @property + def password(self): + """ + Returns the GNS3 VM password. + + :returns: VM password + """ + return self._current_engine().password + + @property + def port(self): + """ + Returns the GNS3 VM port. + + :returns: VM port + """ + return self._current_engine().port + + @property + def protocol(self): + """ + Returns the GNS3 VM protocol. + + :returns: VM protocol + """ + return self._current_engine().protocol + + @property + def enable(self): + """ + The GNSVM is activated + """ + return self._settings["enable"] + @property def settings(self): return self._settings @@ -99,3 +157,15 @@ class GNS3VM: for vm in (yield from engine.list()): vms.append({"vmname": vm["vmname"]}) return vms + + @asyncio.coroutine + def start(self): + """ + Start the GNS3 VM + """ + engine = self._current_engine() + if not engine.running: + log.info("Start the GNS3 VM") + engine.vmname = self._settings["vmname"] + yield from engine.start() + diff --git a/gns3server/controller/gns3vm/base_gns3_vm.py b/gns3server/controller/gns3vm/base_gns3_vm.py index a92b0caf..b9f38c13 100644 --- a/gns3server/controller/gns3vm/base_gns3_vm.py +++ b/gns3server/controller/gns3vm/base_gns3_vm.py @@ -33,15 +33,21 @@ class BaseGNS3VM: self._headless = False self._vcpus = 1 self._ram = 1024 + self._user = "" + self.password = "" + self._protocol = "http" self._running = False # limit the number of vCPUs to the number of physical cores (hyper thread CPUs are excluded) # because this is likely to degrade performances. self._vcpus = psutil.cpu_count(logical=False) # we want to allocate half of the available physical memory - ram = int(psutil.virtual_memory().total / (1024 * 1024) / 2) + #ram = int(psutil.virtual_memory().total / (1024 * 1024) / 2) # value must be a multiple of 4 (VMware requirement) - ram -= ram % 4 + #ram -= ram % 4 + + ram = 2048 + self._ram = ram @property @@ -64,6 +70,60 @@ class BaseGNS3VM: self._vmname = new_name + @property + def protocol(self): + """ + Get the GNS3 VM protocol + + :returns: Protocol as string + """ + return self._protocol + + @protocol.setter + def protocol(self, val): + """ + Sets the GNS3 VM protocol + + :param val: new VM protocol + """ + self._protocol = val + + @property + def user(self): + """ + Get the GNS3 VM user + + :returns: User as string + """ + return self._user + + @user.setter + def user(self, val): + """ + Sets the GNS3 VM user + + :param val: new VM user + """ + self._user = val + + @property + def password(self): + """ + Get the GNS3 VM password + + :returns: Password as string + """ + return self._password + + @password.setter + def password(self, val): + """ + Sets the GNS3 VM password + + :param val: new VM password + """ + self._password = val + @property def port(self): """ diff --git a/gns3server/controller/gns3vm/vmware_gns3_vm.py b/gns3server/controller/gns3vm/vmware_gns3_vm.py index e17379a8..7e50c46a 100644 --- a/gns3server/controller/gns3vm/vmware_gns3_vm.py +++ b/gns3server/controller/gns3vm/vmware_gns3_vm.py @@ -59,9 +59,10 @@ class VMwareGNS3VM(BaseGNS3VM): available_ram = int(psutil.virtual_memory().available / (1024 * 1024)) if ram > available_ram: - raise GNS3VMError("You have allocated too much memory for the GNS3 VM! (available memory is {} MB)".format(available_ram)) + raise GNS3VMError("You have allocated too much memory ({} MB) for the GNS3 VM! (available memory is {} MB)".format(ram, available_ram)) # memory must be a multiple of 4 (VMware requirement) + if ram % 4 != 0: raise GNS3VMError("Allocated memory for the GNS3 VM must be a multiple of 4".format(available_ram)) @@ -100,12 +101,12 @@ class VMwareGNS3VM(BaseGNS3VM): # check we have a valid VMX file path if not self._vmx_path: - raise GNS3VMError("GNS3 VM is not configured") + raise GNS3VMError("VMWare VM {} not found".format(self.vmname)) if not os.path.exists(self._vmx_path): raise GNS3VMError("VMware VMX file {} doesn't exist".format(self._vmx_path)) # set the number of vCPUs and amount of RAM - yield from self._set_vcpus_ram(self.vcpus, self.ram) + #yield from self._set_vcpus_ram(self.vcpus, self.ram) # start the VM args = [self._vmx_path] diff --git a/tests/controller/test_controller.py b/tests/controller/test_controller.py index 96b9d373..382dbd17 100644 --- a/tests/controller/test_controller.py +++ b/tests/controller/test_controller.py @@ -19,6 +19,7 @@ import os import uuid import json import pytest +import socket import aiohttp from unittest.mock import MagicMock from tests.utils import AsyncioMagicMock, asyncio_patch @@ -252,6 +253,28 @@ def test_getProject(controller, async_run): assert controller.get_project("dsdssd") +def test_start(controller, async_run): + async_run(controller.start()) + assert len(controller.computes) == 1 # Local compute is created + assert controller.computes["local"].name == socket.gethostname() + + +def test_start_vm(controller, async_run): + """ + Start the controller with a GNS3 VM + """ + controller.gns3vm.settings = { + "enable": True, + "engine": "vmware" + } + with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.start") as mock: + async_run(controller.start()) + assert mock.called + assert len(controller.computes) == 2 # Local compute and vm are created + assert "local" in controller.computes + assert "vm" in controller.computes + + def test_stop(controller, async_run): c = async_run(controller.add_compute(compute_id="test1")) c._connected = True