Allocate application IDs for IOU nodes on the controller.

An application ID is used by IOU to generate its interface Mac addresses. They must be unique across all opened projects sharing the same computes to avoid Mac address collisions.
This commit is contained in:
grossmj committed 2020-02-10 15:20:49 +08:00
1 parent 6cb87ef25d
commit c5412bf970
10 files changed
+194 -119

No files matched your search

-79
View File
@@ -1,79 +0,0 @@
# -*- 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/>.
import pytest
from unittest.mock import patch
import uuid
import sys
pytestmark = pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
if not sys.platform.startswith("win"):
from gns3server.compute.iou import IOU
from gns3server.compute.iou.iou_error import IOUError
from gns3server.compute.project_manager import ProjectManager
@pytest.fixture(scope="function")
def iou(port_manager):
# Cleanup the IOU object
IOU._instance = None
iou = IOU.instance()
iou.port_manager = port_manager
return iou
def test_application_id(loop, project, iou):
vm1_id = str(uuid.uuid4())
vm2_id = str(uuid.uuid4())
vm3_id = str(uuid.uuid4())
vm1 = loop.run_until_complete(iou.create_node("PC 1", project.id, vm1_id))
vm2 = loop.run_until_complete(iou.create_node("PC 2", project.id, vm2_id))
assert vm1.application_id == 1
assert vm2.application_id == 2
loop.run_until_complete(iou.delete_node(vm1_id))
vm3 = loop.run_until_complete(iou.create_node("PC 3", project.id, vm3_id))
assert vm3.application_id == 1
def test_get_application_id_multiple_project(loop, iou):
vm1_id = str(uuid.uuid4())
vm2_id = str(uuid.uuid4())
vm3_id = str(uuid.uuid4())
project1 = ProjectManager.instance().create_project(project_id=str(uuid.uuid4()))
project2 = ProjectManager.instance().create_project(project_id=str(uuid.uuid4()))
vm1 = loop.run_until_complete(iou.create_node("PC 1", project1.id, vm1_id))
vm2 = loop.run_until_complete(iou.create_node("PC 2", project1.id, vm2_id))
vm3 = loop.run_until_complete(iou.create_node("PC 2", project2.id, vm3_id))
assert vm1.application_id == 1
assert vm2.application_id == 2
assert vm3.application_id == 3
def test_get_application_id_no_id_available(loop, project, iou):
with pytest.raises(IOUError):
for i in range(1, 513):
node_id = str(uuid.uuid4())
vm = loop.run_until_complete(iou.create_node("PC {}".format(i), project.id, node_id))
assert vm.application_id == i
def test_get_images_directory(iou, tmpdir):
with patch("gns3server.config.Config.get_section_config", return_value={"images_path": str(tmpdir)}):
assert iou.get_images_directory() == str(tmpdir / "IOU")
+126
View File
@@ -28,6 +28,7 @@ from uuid import uuid4
from gns3server.controller.project import Project
from gns3server.controller.template import Template
from gns3server.controller.node import Node
from gns3server.controller.ports.ethernet_port import EthernetPort
from gns3server.config import Config
@@ -204,6 +205,131 @@ def test_add_node_non_local(async_run, controller):
project.emit_notification.assert_any_call("node.created", node.__json__())
def test_add_node_iou(async_run, controller):
"""
Test if an application ID is allocated for IOU nodes
"""
compute = MagicMock()
compute.id = "local"
project = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test1"))
project.emit_notification = MagicMock()
response = MagicMock()
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project.add_node(compute, "test1", None, node_type="iou"))
node2 = async_run(project.add_node(compute, "test2", None, node_type="iou"))
node3 = async_run(project.add_node(compute, "test3", None, node_type="iou"))
assert node1.properties["application_id"] == 1
assert node2.properties["application_id"] == 2
assert node3.properties["application_id"] == 3
def test_add_node_iou_with_multiple_projects(async_run, controller):
"""
Test if an application ID is allocated for IOU nodes with different projects already opened
"""
compute = MagicMock()
compute.id = "local"
project1 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test1"))
project1.emit_notification = MagicMock()
project2 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test2"))
project2.emit_notification = MagicMock()
project3 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test3"))
project3.emit_notification = MagicMock()
response = MagicMock()
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project1.add_node(compute, "test1", None, node_type="iou"))
node2 = async_run(project1.add_node(compute, "test2", None, node_type="iou"))
node3 = async_run(project1.add_node(compute, "test3", None, node_type="iou"))
node4 = async_run(project2.add_node(compute, "test4", None, node_type="iou"))
node5 = async_run(project2.add_node(compute, "test5", None, node_type="iou"))
node6 = async_run(project2.add_node(compute, "test6", None, node_type="iou"))
node7 = async_run(project3.add_node(compute, "test7", None, node_type="iou"))
node8 = async_run(project3.add_node(compute, "test8", None, node_type="iou"))
node9 = async_run(project3.add_node(compute, "test9", None, node_type="iou"))
assert node1.properties["application_id"] == 1
assert node2.properties["application_id"] == 2
assert node3.properties["application_id"] == 3
assert node4.properties["application_id"] == 4
assert node5.properties["application_id"] == 5
assert node6.properties["application_id"] == 6
assert node7.properties["application_id"] == 7
assert node8.properties["application_id"] == 8
assert node9.properties["application_id"] == 9
controller.remove_project(project1)
project4 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test4"))
project4.emit_notification = MagicMock()
node10 = async_run(project3.add_node(compute, "test10", None, node_type="iou"))
node11 = async_run(project3.add_node(compute, "test11", None, node_type="iou"))
node12 = async_run(project3.add_node(compute, "test12", None, node_type="iou"))
assert node10.properties["application_id"] == 1
assert node11.properties["application_id"] == 2
assert node12.properties["application_id"] == 3
def test_add_node_iou_with_multiple_projects_different_computes(async_run, controller):
"""
Test if an application ID is allocated for IOU nodes with different projects already opened
"""
compute1 = MagicMock()
compute1.id = "remote1"
compute2 = MagicMock()
compute2.id = "remote2"
project1 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test1"))
project1.emit_notification = MagicMock()
project2 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test2"))
project2.emit_notification = MagicMock()
response = MagicMock()
compute1.post = AsyncioMagicMock(return_value=response)
compute2.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project1.add_node(compute1, "test1", None, node_type="iou"))
node2 = async_run(project1.add_node(compute1, "test2", None, node_type="iou"))
node3 = async_run(project2.add_node(compute2, "test3", None, node_type="iou"))
node4 = async_run(project2.add_node(compute2, "test4", None, node_type="iou"))
assert node1.properties["application_id"] == 1
assert node2.properties["application_id"] == 2
assert node3.properties["application_id"] == 1
assert node4.properties["application_id"] == 2
node5 = async_run(project1.add_node(compute2, "test5", None, node_type="iou"))
node6 = async_run(project2.add_node(compute1, "test6", None, node_type="iou"))
assert node5.properties["application_id"] == 3
assert node6.properties["application_id"] == 4
def test_add_node_iou_no_id_available(async_run, controller):
"""
Test if an application ID is allocated for IOU nodes
"""
compute = MagicMock()
compute.id = "local"
project = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test"))
project.emit_notification = MagicMock()
response = MagicMock()
compute.post = AsyncioMagicMock(return_value=response)
with pytest.raises(aiohttp.web.HTTPConflict):
for i in range(1, 513):
prop = {"properties": {"application_id": i}}
project._nodes[i] = Node(project, compute, "Node{}".format(i), node_id=i, node_type="iou", **prop)
async_run(project.add_node(compute, "test1", None, node_type="iou"))
def test_add_node_from_template(async_run, controller):
"""
For a local server we send the project path
+1 -1
View File
@@ -42,7 +42,7 @@ def fake_iou_bin(images_dir):
@pytest.fixture
def base_params(tmpdir, fake_iou_bin):
"""Return standard parameters"""
return {"name": "PC TEST 1", "path": "iou.bin"}
return {"application_id": 42, "name": "PC TEST 1", "path": "iou.bin"}
@pytest.fixture