mirror of
https://github.com/GNS3/gns3-server
synced 2024-12-01 04:38:12 +00:00
Method for reloading a topology (not bind to an api handler)
Ref https://github.com/GNS3/gns3-gui/issues/1243
This commit is contained in:
parent
3aea16c527
commit
742243e9df
@ -26,6 +26,7 @@ from .project import Project
|
||||
from .compute import Compute
|
||||
from .notification import Notification
|
||||
from ..version import __version__
|
||||
from .topology import load_topology
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
@ -185,6 +186,29 @@ class Controller:
|
||||
def remove_project(self, project):
|
||||
del self._projects[project.id]
|
||||
|
||||
@asyncio.coroutine
|
||||
def load_project(self, path):
|
||||
"""
|
||||
Load a project from a .gns3
|
||||
|
||||
:param path: Path of the .gns3
|
||||
"""
|
||||
topo_data = load_topology(path)
|
||||
topology = topo_data.pop("topology")
|
||||
topo_data.pop("version")
|
||||
topo_data.pop("revision")
|
||||
topo_data.pop("type")
|
||||
|
||||
project = yield from self.add_project(path=os.path.dirname(path), **topo_data)
|
||||
|
||||
for compute in topology["computes"]:
|
||||
yield from self.add_compute(**compute)
|
||||
for node in topology["nodes"]:
|
||||
compute = self.get_compute(node.pop("compute_id"))
|
||||
name = node.pop("name")
|
||||
node_id = node.pop("node_id")
|
||||
yield from project.add_node(compute, name, node_id, **node)
|
||||
|
||||
@property
|
||||
def projects(self):
|
||||
"""
|
||||
|
@ -15,8 +15,12 @@
|
||||
# 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 json
|
||||
import aiohttp
|
||||
|
||||
from ..version import __version__
|
||||
|
||||
GNS3_FILE_FORMAT_REVISION = 5
|
||||
|
||||
def project_to_topology(project):
|
||||
"""
|
||||
@ -31,7 +35,7 @@ def project_to_topology(project):
|
||||
"computes": []
|
||||
},
|
||||
"type": "topology",
|
||||
"revision": 5,
|
||||
"revision": GNS3_FILE_FORMAT_REVISION,
|
||||
"version": __version__
|
||||
}
|
||||
|
||||
@ -44,6 +48,20 @@ def project_to_topology(project):
|
||||
for compute in computes:
|
||||
if hasattr(compute, "__json__"):
|
||||
data["topology"]["computes"].append(compute.__json__())
|
||||
print(data)
|
||||
#TODO: check JSON schema
|
||||
return data
|
||||
|
||||
|
||||
def load_topology(path):
|
||||
"""
|
||||
Open a topology file, patch it for last GNS3 release and return it
|
||||
"""
|
||||
try:
|
||||
with open(path) as f:
|
||||
topo = json.load(f)
|
||||
except OSError as e:
|
||||
raise aiohttp.web.HTTPConflict(text="Could not load topology {}: {}".format(path, str(e)))
|
||||
#TODO: Check JSON schema
|
||||
if topo["revision"] < GNS3_FILE_FORMAT_REVISION:
|
||||
raise aiohttp.web.HTTPConflict(text="Old GNS3 project are not yet supported")
|
||||
return topo
|
||||
|
@ -21,7 +21,7 @@ import json
|
||||
import pytest
|
||||
import aiohttp
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from tests.utils import AsyncioMagicMock
|
||||
|
||||
from gns3server.controller import Controller
|
||||
from gns3server.controller.compute import Compute
|
||||
@ -184,3 +184,71 @@ def test_close(controller, async_run):
|
||||
c._connected = True
|
||||
async_run(controller.close())
|
||||
assert c.connected is False
|
||||
|
||||
|
||||
def test_load_project(controller, async_run, tmpdir):
|
||||
data = {
|
||||
"name": "Test",
|
||||
"project_id": "c8d07a5a-134f-4c3f-8599-e35eac85eb17",
|
||||
"revision": 5,
|
||||
"type": "topology",
|
||||
"version": "2.0.0dev1",
|
||||
"topology": {
|
||||
"computes": [
|
||||
{
|
||||
"compute_id": "my_remote",
|
||||
"host": "127.0.0.1",
|
||||
"name": "My remote",
|
||||
"port": 3080,
|
||||
"protocol": "http",
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"capturing": True,
|
||||
"link_id": "c44331d2-2da4-490d-9aad-7f5c126ae271",
|
||||
"nodes": [
|
||||
{"node_id": "c067b922-7f77-4680-ac00-0226c6583598", "adapter_number": 0, "port_number": 0},
|
||||
{"node_id": "50d66d7b-0dd7-4e9f-b720-6eb621ae6543", "adapter_number": 0, "port_number": 0},
|
||||
],
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"compute_id": "my_remote",
|
||||
"name": "PC2",
|
||||
"node_id": "c067b922-7f77-4680-ac00-0226c6583598",
|
||||
"node_type": "vpcs",
|
||||
"properties": {
|
||||
"startup_script": "set pcname PC2\n",
|
||||
"startup_script_path": "startup.vpc"
|
||||
},
|
||||
},
|
||||
{
|
||||
"compute_id": "my_remote",
|
||||
"name": "PC1",
|
||||
"node_id": "50d66d7b-0dd7-4e9f-b720-6eb621ae6543",
|
||||
"node_type": "vpcs",
|
||||
"properties": {
|
||||
"startup_script": "set pcname PC1\n",
|
||||
"startup_script_path": "startup.vpc"
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
with open(str(tmpdir / "test.gns3"), "w+") as f:
|
||||
json.dump(data, f)
|
||||
controller.add_compute = AsyncioMagicMock()
|
||||
mock_project = MagicMock()
|
||||
controller.add_project = AsyncioMagicMock(return_value=mock_project)
|
||||
controller._computes["my_remote"] = MagicMock()
|
||||
|
||||
async_run(controller.load_project(str(tmpdir / "test.gns3")))
|
||||
|
||||
controller.add_compute.assert_called_with(compute_id='my_remote', host='127.0.0.1', name='My remote', port=3080, protocol='http')
|
||||
controller.add_project.assert_called_with(name='Test', project_id='c8d07a5a-134f-4c3f-8599-e35eac85eb17', path=str(tmpdir))
|
||||
|
||||
mock_project.add_node.assert_any_call(controller._computes["my_remote"], 'PC1', '50d66d7b-0dd7-4e9f-b720-6eb621ae6543', node_type='vpcs', properties={'startup_script': 'set pcname PC1\n', 'startup_script_path': 'startup.vpc'})
|
||||
mock_project.add_node.assert_any_call(controller._computes["my_remote"], 'PC2', 'c067b922-7f77-4680-ac00-0226c6583598', node_type='vpcs', properties={'startup_script': 'set pcname PC2\n', 'startup_script_path': 'startup.vpc'})
|
||||
|
||||
|
@ -15,12 +15,15 @@
|
||||
# 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 json
|
||||
import pytest
|
||||
import aiohttp
|
||||
from unittest.mock import MagicMock
|
||||
from tests.utils import asyncio_patch
|
||||
|
||||
from gns3server.controller.project import Project
|
||||
from gns3server.controller.compute import Compute
|
||||
from gns3server.controller.topology import project_to_topology
|
||||
from gns3server.controller.topology import project_to_topology, load_topology
|
||||
from gns3server.version import __version__
|
||||
|
||||
|
||||
@ -60,3 +63,45 @@ def test_basic_topology(tmpdir, async_run, controller):
|
||||
assert topo["topology"]["links"][0] == link.__json__()
|
||||
assert topo["topology"]["computes"][0] == compute.__json__()
|
||||
|
||||
|
||||
|
||||
def test_load_topology(tmpdir):
|
||||
data = {
|
||||
"project_id": "69f26504-7aa3-48aa-9f29-798d44841211",
|
||||
"name": "Test",
|
||||
"revision": 5,
|
||||
"topology": {
|
||||
"nodes": [],
|
||||
"links": [],
|
||||
"computes": []
|
||||
},
|
||||
"type": "topology",
|
||||
"version": __version__}
|
||||
|
||||
path = str(tmpdir / "test.gns3")
|
||||
with open(path, "w+") as f:
|
||||
json.dump(data, f)
|
||||
topo = load_topology(path)
|
||||
assert topo == data
|
||||
|
||||
def test_load_topology_file_error(tmpdir):
|
||||
path = str(tmpdir / "test.gns3")
|
||||
with pytest.raises(aiohttp.web.HTTPConflict):
|
||||
topo = load_topology(path)
|
||||
|
||||
|
||||
def test_load_old_topology(tmpdir):
|
||||
data = {
|
||||
"project_id": "69f26504-7aa3-48aa-9f29-798d44841211",
|
||||
"name": "Test",
|
||||
"revision": 4,
|
||||
"topology": {
|
||||
},
|
||||
"type": "topology",
|
||||
"version": __version__}
|
||||
|
||||
path = str(tmpdir / "test.gns3")
|
||||
with open(path, "w+") as f:
|
||||
json.dump(data, f)
|
||||
with pytest.raises(aiohttp.web.HTTPConflict):
|
||||
topo = load_topology(path)
|
||||
|
Loading…
Reference in New Issue
Block a user