1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-28 11:18:11 +00:00

Avoid to corrupt project in case of error during loading

Fix #651
This commit is contained in:
Julien Duponchelle 2016-09-05 17:28:49 +02:00
parent 75d5f6507d
commit 5ae456d6e2
No known key found for this signature in database
GPG Key ID: CE8B29639E07F5E8
2 changed files with 43 additions and 6 deletions

View File

@ -570,7 +570,10 @@ class Project:
self._status = "opened" self._status = "opened"
path = self._topology_file() path = self._topology_file()
if os.path.exists(path): if not os.path.exists(path):
return
shutil.copy(path, path + ".backup")
try:
topology = load_topology(path)["topology"] topology = load_topology(path)["topology"]
for compute in topology.get("computes", []): for compute in topology.get("computes", []):
yield from self.controller.add_compute(**compute) yield from self.controller.add_compute(**compute)
@ -584,13 +587,25 @@ class Project:
for node_link in link_data["nodes"]: for node_link in link_data["nodes"]:
node = self.get_node(node_link["node_id"]) node = self.get_node(node_link["node_id"])
yield from link.add_node(node, node_link["adapter_number"], node_link["port_number"], label=node_link.get("label")) yield from link.add_node(node, node_link["adapter_number"], node_link["port_number"], label=node_link.get("label"))
for drawing_data in topology.get("drawings", []): for drawing_data in topology.get("drawings", []):
drawing = yield from self.add_drawing(**drawing_data) drawing = yield from self.add_drawing(**drawing_data)
# Should we start the nodes when project is open # We catch all error to be able to rollback the .gns3 to the previous state
if self._auto_start: except Exception as e:
yield from self.start_all() for compute in self._project_created_on_compute:
try:
yield from compute.post("/projects/{}/close".format(self._id))
# We don't care if a compute is down at this step
except (aiohttp.errors.ClientOSError, aiohttp.web.HTTPNotFound, aiohttp.web.HTTPConflict):
pass
shutil.copy(path + ".backup", path)
self._status = "closed"
raise e
os.remove(path + ".backup")
# Should we start the nodes when project is open
if self._auto_start:
yield from self.start_all()
@open_required @open_required
@asyncio.coroutine @asyncio.coroutine

View File

@ -15,13 +15,16 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import json import json
import pytest import pytest
import aiohttp
from tests.utils import asyncio_patch, AsyncioMagicMock from tests.utils import asyncio_patch, AsyncioMagicMock
from gns3server.controller.compute import Compute from gns3server.controller.compute import Compute
@pytest.fixture @pytest.fixture
def demo_topology(): def demo_topology():
""" """
@ -112,7 +115,7 @@ def demo_topology():
"z": 1 "z": 1
}, },
{ {
"compute_id": "local", "compute_id": "vm",
"console": 5001, "console": 5001,
"console_type": "telnet", "console_type": "telnet",
"height": 59, "height": 59,
@ -148,6 +151,7 @@ def test_open(controller, tmpdir, demo_topology, async_run, http_server):
json.dump(demo_topology, f) json.dump(demo_topology, f)
controller._computes["local"] = Compute("local", controller=controller, host=http_server[0], port=http_server[1]) controller._computes["local"] = Compute("local", controller=controller, host=http_server[0], port=http_server[1])
controller._computes["vm"] = controller._computes["local"]
project = async_run(controller.load_project(str(tmpdir / "demo.gns3"))) project = async_run(controller.load_project(str(tmpdir / "demo.gns3")))
assert project.status == "opened" assert project.status == "opened"
@ -159,3 +163,21 @@ def test_open(controller, tmpdir, demo_topology, async_run, http_server):
assert len(project.drawings) == 1 assert len(project.drawings) == 1
assert project.name == "demo" assert project.name == "demo"
def test_open_missing_compute(controller, tmpdir, demo_topology, async_run, http_server):
"""
If a compute is missing the project should not be open and the .gns3 should
be the one before opening the project
"""
with open(str(tmpdir / "demo.gns3"), "w+") as f:
json.dump(demo_topology, f)
controller._computes["local"] = Compute("local", controller=controller, host=http_server[0], port=http_server[1])
with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
project = async_run(controller.load_project(str(tmpdir / "demo.gns3")))
assert controller.get_project("3c1be6f9-b4ba-4737-b209-63c47c23359f").status == "closed"
with open(str(tmpdir / "demo.gns3"), "r") as f:
topo = json.load(f)
assert len(topo["topology"]["nodes"]) == 2