API for duplicate a project

Ref https://github.com/GNS3/gns3-gui/issues/995
This commit is contained in:
Julien Duponchelle committed 2016-07-25 16:26:33 +02:00
1 parent fb3b6b62f5
commit f357879186
9 files changed
+285 -57

No files matched your search

+57 -2
View File
@@ -17,9 +17,11 @@
import os
import json
import uuid
import shutil
import asyncio
import aiohttp
import shutil
import tempfile
from uuid import UUID, uuid4
@@ -29,12 +31,26 @@ from .topology import project_to_topology, load_topology
from .udp_link import UDPLink
from ..config import Config
from ..utils.path import check_path_allowed, get_default_project_directory
from .export_project import export_project
from .import_project import import_project
import logging
log = logging.getLogger(__name__)
def open_required(func):
"""
Use this decorator to raise an error if the project is not opened
"""
def wrapper(self, *args, **kwargs):
if self._status == "closed":
raise aiohttp.web.HTTPForbidden(text="The project is not opened")
return func(self, *args, **kwargs)
return wrapper
class Project:
"""
A project inside a controller
@@ -74,8 +90,13 @@ class Project:
self._filename = filename
else:
self._filename = self.name + ".gns3"
self.reset()
# At project creation we write an empty .gns3
if not os.path.exists(self._topology_file()):
self.dump()
def reset(self):
"""
Called when open/close a project. Cleanup internal stuff
@@ -212,6 +233,7 @@ class Project:
return self.update_allocated_node_name(new_name)
return new_name
@open_required
@asyncio.coroutine
def add_node(self, compute, name, node_id, **kwargs):
"""
@@ -243,6 +265,7 @@ class Project:
return node
return self._nodes[node_id]
@open_required
@asyncio.coroutine
def delete_node(self, node_id):
@@ -258,6 +281,7 @@ class Project:
self.dump()
self.controller.notification.emit("node.deleted", node.__json__())
@open_required
def get_node(self, node_id):
"""
Return the node or raise a 404 if the node is unknown
@@ -281,6 +305,7 @@ class Project:
"""
return self._drawings
@open_required
@asyncio.coroutine
def add_drawing(self, drawing_id=None, **kwargs):
"""
@@ -296,6 +321,7 @@ class Project:
return drawing
return self._drawings[drawing_id]
@open_required
def get_drawing(self, drawing_id):
"""
Return the Drawing or raise a 404 if the drawing is unknown
@@ -305,6 +331,7 @@ class Project:
except KeyError:
raise aiohttp.web.HTTPNotFound(text="Drawing ID {} doesn't exist".format(drawing_id))
@open_required
@asyncio.coroutine
def delete_drawing(self, drawing_id):
drawing = self.get_drawing(drawing_id)
@@ -312,6 +339,7 @@ class Project:
self.dump()
self.controller.notification.emit("drawing.deleted", drawing.__json__())
@open_required
@asyncio.coroutine
def add_link(self, link_id=None):
"""
@@ -324,6 +352,7 @@ class Project:
self.dump()
return link
@open_required
@asyncio.coroutine
def delete_link(self, link_id):
link = self.get_link(link_id)
@@ -332,6 +361,7 @@ class Project:
self.dump()
self.controller.notification.emit("link.deleted", link.__json__())
@open_required
def get_link(self, link_id):
"""
Return the Link or raise a 404 if the link is unknown
@@ -371,6 +401,7 @@ class Project:
except OSError as e:
log.warning(str(e))
@open_required
@asyncio.coroutine
def delete(self):
yield from self.close()
@@ -406,6 +437,8 @@ class Project:
return
self.reset()
self._status = "opened"
path = self._topology_file()
if os.path.exists(path):
topology = load_topology(path)["topology"]
@@ -424,7 +457,29 @@ class Project:
for drawing_data in topology.get("drawings", []):
drawing = yield from self.add_drawing(**drawing_data)
self._status = "opened"
@open_required
@asyncio.coroutine
def duplicate(self, name=None, location=None):
"""
Duplicate a project
It's the save as feature of the 1.X. It's implemented on top of the
export / import features. It will generate a gns3p and reimport it.
It's a little slower but we have only one implementation to maintain.
:param name: Name of the new project. A new one will be generated in case of conflicts
:param location: Parent directory of the new project
"""
with tempfile.TemporaryDirectory() as tmpdir:
zipstream = yield from export_project(self, tmpdir, keep_compute_id=True, allow_all_nodes=True)
with open(os.path.join(tmpdir, "project.gns3p"), "wb+") as f:
for data in zipstream:
f.write(data)
with open(os.path.join(tmpdir, "project.gns3p"), "rb") as f:
project = yield from import_project(self._controller, str(uuid.uuid4()), f, location=location, name=name, keep_compute_id=True)
return project
def is_running(self):
"""