diff --git a/gns3server/modules/base_manager.py b/gns3server/modules/base_manager.py index 33206f37..992a1b29 100644 --- a/gns3server/modules/base_manager.py +++ b/gns3server/modules/base_manager.py @@ -49,13 +49,6 @@ class BaseManager: cls._instance = cls() return cls._instance - def __del__(self): - self.destroy() - - def destroy(): - """Cleanup the VMS. Call this before closing the server""" - cls._instance() - @property def module_name(self): """ diff --git a/gns3server/modules/vpcs/__init__.py b/gns3server/modules/vpcs/__init__.py index 6ad5d8cc..dbabf8ca 100644 --- a/gns3server/modules/vpcs/__init__.py +++ b/gns3server/modules/vpcs/__init__.py @@ -19,9 +19,45 @@ VPCS server module. """ +import asyncio + from ..base_manager import BaseManager +from .vpcs_error import VPCSError from .vpcs_vm import VPCSVM class VPCS(BaseManager): _VM_CLASS = VPCSVM + + def __init__(self): + super().__init__() + self._free_mac_ids = list(range(0, 255)) + self._used_mac_ids = {} + + @asyncio.coroutine + def create_vm(self, *args, **kwargs): + + vm = yield from super().create_vm(*args, **kwargs) + try: + self._used_mac_ids[vm.uuid] = self._free_mac_ids.pop(0) + except IndexError: + raise VPCSError("No mac address available") + return vm + + @asyncio.coroutine + def delete_vm(self, uuid, *args, **kwargs): + + i = self._used_mac_ids[uuid] + self._free_mac_ids.insert(0, i) + del self._used_mac_ids[uuid] + yield from super().delete_vm(uuid, *args, **kwargs) + + def get_mac_id(self, vm_uuid): + """ + Get an unique VPCS mac id + + :param vm_uuid: UUID of the VPCS vm + :returns: VPCS Mac id + """ + + return self._used_mac_ids.get(vm_uuid, 1) diff --git a/gns3server/modules/vpcs/vpcs_vm.py b/gns3server/modules/vpcs/vpcs_vm.py index fa80e5e9..1e60b348 100644 --- a/gns3server/modules/vpcs/vpcs_vm.py +++ b/gns3server/modules/vpcs/vpcs_vm.py @@ -415,8 +415,7 @@ class VPCSVM(BaseVM): command.extend(["-e"]) command.extend(["-d", nio.tap_vm]) - # FIXME: find workaround - # command.extend(["-m", str(self._id)]) # the unique ID is used to set the MAC address offset + command.extend(["-m", str(self._manager.get_mac_id(self._uuid))]) # the unique ID is used to set the MAC address offset command.extend(["-i", "1"]) # option to start only one VPC instance command.extend(["-F"]) # option to avoid the daemonization of VPCS if self._script_file: diff --git a/tests/conftest.py b/tests/conftest.py index 572e3f00..537b1663 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -53,6 +53,8 @@ def _get_unused_port(): @pytest.fixture(scope="session") def server(request, loop, port_manager): + """A GNS 3 server""" + port = _get_unused_port() host = "localhost" app = web.Application() @@ -75,16 +77,22 @@ def server(request, loop, port_manager): @pytest.fixture(scope="module") def project(): + """A GNS3 lab""" + return ProjectManager.instance().create_project(uuid="a1e920ca-338a-4e9f-b363-aa607b09dd80") @pytest.fixture(scope="session") def port_manager(): + """An instance of port manager""" + return PortManager("127.0.0.1", False) @pytest.fixture(scope="function") def free_console_port(request, port_manager): + """Get a free TCP port""" + # In case of already use ports we will raise an exception port = port_manager.get_free_console_port() # We release the port immediately in order to allow diff --git a/tests/modules/vpcs/test_vpcs_manager.py b/tests/modules/vpcs/test_vpcs_manager.py new file mode 100644 index 00000000..a239c1c1 --- /dev/null +++ b/tests/modules/vpcs/test_vpcs_manager.py @@ -0,0 +1,56 @@ +# -*- 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 . + + +import pytest +import asyncio +import uuid + + +from gns3server.modules.vpcs import VPCS +from gns3server.modules.vpcs.vpcs_error import VPCSError +from gns3server.modules.project_manager import ProjectManager + + +def test_get_mac_id(loop, project, port_manager): + # Cleanup the VPCS object + VPCS._instance = None + vpcs = VPCS.instance() + vpcs.port_manager = port_manager + vm1_uuid = str(uuid.uuid4()) + vm2_uuid = str(uuid.uuid4()) + vm3_uuid = str(uuid.uuid4()) + loop.run_until_complete(vpcs.create_vm("PC 1", project.uuid, vm1_uuid)) + loop.run_until_complete(vpcs.create_vm("PC 2", project.uuid, vm2_uuid)) + assert vpcs.get_mac_id(vm1_uuid) == 0 + assert vpcs.get_mac_id(vm1_uuid) == 0 + assert vpcs.get_mac_id(vm2_uuid) == 1 + loop.run_until_complete(vpcs.delete_vm(vm1_uuid)) + loop.run_until_complete(vpcs.create_vm("PC 3", project.uuid, vm3_uuid)) + assert vpcs.get_mac_id(vm3_uuid) == 0 + + +def test_get_mac_id_no_id_available(loop, project, port_manager): + # Cleanup the VPCS object + VPCS._instance = None + vpcs = VPCS.instance() + vpcs.port_manager = port_manager + with pytest.raises(VPCSError): + for i in range(0, 256): + vm_uuid = str(uuid.uuid4()) + loop.run_until_complete(vpcs.create_vm("PC {}".format(i), project.uuid, vm_uuid)) + assert vpcs.get_mac_id(vm_uuid) == i