Skip to content

Commit

Permalink
Wait for the end of project loading before making new change
Browse files Browse the repository at this point in the history
Fix #790
  • Loading branch information
julien-duponchelle committed Nov 18, 2016
1 parent 5ab85e5 commit 40af2a3
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 44 deletions.
13 changes: 12 additions & 1 deletion gns3server/controller/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,13 +338,24 @@ def add_project(self, project_id=None, name=None, **kwargs):

def get_project(self, project_id):
"""
Returns a compute server or raise a 404 error.
Returns a project or raise a 404 error.
"""
try:
return self._projects[project_id]
except KeyError:
raise aiohttp.web.HTTPNotFound(text="Project ID {} doesn't exist".format(project_id))

@asyncio.coroutine
def get_loaded_project(self, project_id):
"""
Returns a project or raise a 404 error.
If project is not finished to load wait for it
"""
project = self.get_project(project_id)
yield from project.wait_loaded()
return project

def remove_project(self, project):
del self._projects[project.id]

Expand Down
13 changes: 13 additions & 0 deletions gns3server/controller/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def __init__(self, name=None, project_id=None, path=None, controller=None, statu
self._status = status
self._scene_height = scene_height
self._scene_width = scene_width
self._loading = False

# Disallow overwrite of existing project
if project_id is None and path is not None:
Expand Down Expand Up @@ -618,10 +619,12 @@ def open(self):
return

self.reset()
self._loading = True
self._status = "opened"

path = self._topology_file()
if not os.path.exists(path):
self._loading = False
return
try:
shutil.copy(path, path + ".backup")
Expand Down Expand Up @@ -655,16 +658,26 @@ def open(self):
if os.path.exists(path + ".backup"):
shutil.copy(path + ".backup", path)
self._status = "closed"
self._loading = False
raise e
try:
os.remove(path + ".backup")
except OSError:
pass

self._loading = False
# Should we start the nodes when project is open
if self._auto_start:
yield from self.start_all()

@asyncio.coroutine
def wait_loaded(self):
"""
Wait until the project finish loading
"""
while self._loading:
yield from asyncio.sleep(0.5)

@asyncio.coroutine
def duplicate(self, name=None, location=None):
"""
Expand Down
12 changes: 4 additions & 8 deletions gns3server/handlers/api/controller/drawing_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ class DrawingHandler:
description="List drawings of a project")
def list_drawings(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
response.json([v for v in project.drawings.values()])

@Route.post(
Expand All @@ -59,8 +58,7 @@ def list_drawings(request, response):
output=DRAWING_OBJECT_SCHEMA)
def create(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
drawing = yield from project.add_drawing(**request.json)
response.set_status(201)
response.json(drawing)
Expand All @@ -80,8 +78,7 @@ def create(request, response):
output=DRAWING_OBJECT_SCHEMA)
def update(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
drawing = project.get_drawing(request.match_info["drawing_id"])
yield from drawing.update(**request.json)
response.set_status(201)
Expand All @@ -100,7 +97,6 @@ def update(request, response):
description="Delete a drawing instance")
def delete(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
yield from project.delete_drawing(request.match_info["drawing_id"])
response.set_status(204)
21 changes: 7 additions & 14 deletions gns3server/handlers/api/controller/link_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ class LinkHandler:
description="List links of a project")
def list_links(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
response.json([v for v in project.links.values()])

@Route.post(
Expand All @@ -61,8 +60,7 @@ def list_links(request, response):
output=LINK_OBJECT_SCHEMA)
def create(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
link = yield from project.add_link()
try:
for node in request.json["nodes"]:
Expand Down Expand Up @@ -91,8 +89,7 @@ def create(request, response):
output=LINK_OBJECT_SCHEMA)
def update(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
link = project.get_link(request.match_info["link_id"])
yield from link.update_nodes(request.json["nodes"])
response.set_status(201)
Expand All @@ -113,8 +110,7 @@ def update(request, response):
description="Start capture on a link instance. By default we consider it as an Ethernet link")
def start_capture(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
link = project.get_link(request.match_info["link_id"])
yield from link.start_capture(data_link_type=request.json.get("data_link_type", "DLT_EN10MB"), capture_file_name=request.json.get("capture_file_name"))
response.set_status(201)
Expand All @@ -133,8 +129,7 @@ def start_capture(request, response):
description="Stop capture on a link instance")
def stop_capture(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
link = project.get_link(request.match_info["link_id"])
yield from link.stop_capture()
response.set_status(201)
Expand All @@ -153,8 +148,7 @@ def stop_capture(request, response):
description="Delete a link instance")
def delete(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
yield from project.delete_link(request.match_info["link_id"])
response.set_status(204)

Expand All @@ -172,8 +166,7 @@ def delete(request, response):
})
def pcap(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
link = project.get_link(request.match_info["link_id"])

if link.capture_file_path is None:
Expand Down
33 changes: 16 additions & 17 deletions gns3server/handlers/api/controller/node_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def create(request, response):

controller = Controller.instance()
compute = controller.get_compute(request.json.pop("compute_id"))
project = controller.get_project(request.match_info["project_id"])
project = yield from controller.get_loaded_project(request.match_info["project_id"])
node = yield from project.add_node(compute, request.json.pop("name"), request.json.pop("node_id", None), **request.json)
response.set_status(201)
response.json(node)
Expand Down Expand Up @@ -80,8 +80,7 @@ def get_node(request, response):
description="List nodes of a project")
def list_nodes(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
response.json([v for v in project.nodes.values()])

@Route.put(
Expand All @@ -95,7 +94,7 @@ def list_nodes(request, response):
input=NODE_UPDATE_SCHEMA,
output=NODE_OBJECT_SCHEMA)
def update(request, response):
project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
node = project.get_node(request.match_info["node_id"])

# Ignore these because we only use them when creating a node
Expand All @@ -121,7 +120,7 @@ def update(request, response):
output=NODE_OBJECT_SCHEMA)
def start_all(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
yield from project.start_all()
response.set_status(204)

Expand All @@ -139,7 +138,7 @@ def start_all(request, response):
output=NODE_OBJECT_SCHEMA)
def stop_all(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
yield from project.stop_all()
response.set_status(204)

Expand All @@ -157,7 +156,7 @@ def stop_all(request, response):
output=NODE_OBJECT_SCHEMA)
def suspend_all(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
yield from project.suspend_all()
response.set_status(204)

Expand All @@ -175,7 +174,7 @@ def suspend_all(request, response):
output=NODE_OBJECT_SCHEMA)
def reload_all(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
yield from project.stop_all()
yield from project.start_all()
response.set_status(204)
Expand All @@ -195,7 +194,7 @@ def reload_all(request, response):
output=NODE_OBJECT_SCHEMA)
def start(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
node = project.get_node(request.match_info["node_id"])
yield from node.start()
response.json(node)
Expand All @@ -216,7 +215,7 @@ def start(request, response):
output=NODE_OBJECT_SCHEMA)
def stop(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
node = project.get_node(request.match_info["node_id"])
yield from node.stop()
response.json(node)
Expand All @@ -237,7 +236,7 @@ def stop(request, response):
output=NODE_OBJECT_SCHEMA)
def suspend(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
node = project.get_node(request.match_info["node_id"])
yield from node.suspend()
response.json(node)
Expand All @@ -258,7 +257,7 @@ def suspend(request, response):
output=NODE_OBJECT_SCHEMA)
def reload(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
node = project.get_node(request.match_info["node_id"])
yield from node.reload()
response.json(node)
Expand All @@ -277,7 +276,7 @@ def reload(request, response):
},
description="Delete a node instance")
def delete(request, response):
project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
yield from project.delete_node(request.match_info["node_id"])
response.set_status(204)

Expand All @@ -295,7 +294,7 @@ def delete(request, response):
description="Compute the IDLE PC for a Dynamips node")
def auto_idlepc(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
node = project.get_node(request.match_info["node_id"])
idle = yield from node.dynamips_auto_idlepc()
response.json(idle)
Expand All @@ -315,7 +314,7 @@ def auto_idlepc(request, response):
description="Compute a list of potential idle PC for a node")
def idlepc_proposals(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
node = project.get_node(request.match_info["node_id"])
idle = yield from node.dynamips_idlepc_proposals()
response.json(idle)
Expand All @@ -335,7 +334,7 @@ def idlepc_proposals(request, response):
description="Get a file in the node directory")
def get_file(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
node = project.get_node(request.match_info["node_id"])
path = request.match_info["path"]
path = os.path.normpath(path)
Expand Down Expand Up @@ -375,7 +374,7 @@ def get_file(request, response):
description="Write a file in the node directory")
def post_file(request, response):

project = Controller.instance().get_project(request.match_info["project_id"])
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
node = project.get_node(request.match_info["node_id"])
path = request.match_info["path"]
path = os.path.normpath(path)
Expand Down
8 changes: 4 additions & 4 deletions gns3server/handlers/api/controller/project_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def notification_ws(request, response):
def export_project(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from controller.get_loaded_project(request.match_info["project_id"])

with tempfile.TemporaryDirectory() as tmp_dir:
datas = yield from export_project(project, tmp_dir, include_images=bool(request.get("include_images", "0")))
Expand Down Expand Up @@ -360,7 +360,7 @@ def import_project(request, response):
def duplicate(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from controller.get_loaded_project(request.match_info["project_id"])

if request.json.get("path"):
config = Config.instance()
Expand Down Expand Up @@ -390,7 +390,7 @@ def duplicate(request, response):
def get_file(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from controller.get_loaded_project(request.match_info["project_id"])
path = request.match_info["path"]
path = os.path.normpath(path)

Expand Down Expand Up @@ -434,7 +434,7 @@ def get_file(request, response):
def write_file(request, response):

controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
project = yield from controller.get_loaded_project(request.match_info["project_id"])
path = request.match_info["path"]
path = os.path.normpath(path)

Expand Down

0 comments on commit 40af2a3

Please sign in to comment.