Update project API

This commit is contained in:
Julien Duponchelle 2016-08-15 16:44:09 +02:00
parent 431bd789cb
commit 3ca4edef93
No known key found for this signature in database
GPG Key ID: CE8B29639E07F5E8
9 changed files with 74 additions and 54 deletions

View File

@ -126,6 +126,14 @@ Drawing has been deleted.
.. literalinclude:: api/notifications/drawing.deleted.json .. literalinclude:: api/notifications/drawing.deleted.json
project.updated
---------------
Project has been updated.
.. literalinclude:: api/notifications/project.updated.json
project.closed project.closed
--------------- ---------------

View File

@ -278,16 +278,6 @@ class BaseManager:
if node.id in self._nodes: if node.id in self._nodes:
del self._nodes[node.id] del self._nodes[node.id]
@asyncio.coroutine
def project_moved(self, project):
"""
Called when a project is moved
:param project: project instance
"""
pass
@asyncio.coroutine @asyncio.coroutine
def delete_node(self, node_id): def delete_node(self, node_id):
""" """

View File

@ -223,22 +223,6 @@ class Dynamips(BaseManager):
if project.id in self._dynamips_ids: if project.id in self._dynamips_ids:
del self._dynamips_ids[project.id] del self._dynamips_ids[project.id]
@asyncio.coroutine
def project_moved(self, project):
"""
Called when a project is moved.
:param project: Project instance
"""
for node in self._nodes.values():
if node.project.id == project.id:
yield from node.hypervisor.set_working_dir(project.module_working_directory(self.module_name.lower()))
for device in self._devices.values():
if device.project.id == project.id:
yield from device.hypervisor.set_working_dir(project.module_working_directory(self.module_name.lower()))
@property @property
def dynamips_path(self): def dynamips_path(self):
""" """

View File

@ -98,6 +98,24 @@ class Project:
if not os.path.exists(self._topology_file()): if not os.path.exists(self._topology_file()):
self.dump() self.dump()
@asyncio.coroutine
def update(self, **kwargs):
"""
Update the node on the compute server
:param kwargs: Node properties
"""
old_json = self.__json__()
for prop in kwargs:
setattr(self, prop, kwargs[prop])
# We send notif only if object has changed
if old_json != self.__json__():
self.controller.notification.emit("project.updated", self.__json__())
self.dump()
def reset(self): def reset(self):
""" """
Called when open/close a project. Cleanup internal stuff Called when open/close a project. Cleanup internal stuff
@ -131,6 +149,10 @@ class Project:
def name(self): def name(self):
return self._name return self._name
@name.setter
def name(self, val):
self._name = val
@property @property
def id(self): def id(self):
return self._id return self._id
@ -446,7 +468,7 @@ class Project:
self._cleanPictures() self._cleanPictures()
self._status = "closed" self._status = "closed"
if not ignore_notification: if not ignore_notification:
self.controller.notification.emit("project.closed", self.__json__()) self.controller.notification.emit("project.closed", self.__json__())
def _cleanPictures(self): def _cleanPictures(self):
""" """

View File

@ -95,32 +95,6 @@ class ProjectHandler:
project = pm.get_project(request.match_info["project_id"]) project = pm.get_project(request.match_info["project_id"])
response.json(project) response.json(project)
@Route.put(
r"/projects/{project_id}",
description="Update a project",
parameters={
"project_id": "Project UUID",
},
status_codes={
200: "Project updated",
403: "Forbidden to update this project",
404: "The project doesn't exist"
},
output=PROJECT_OBJECT_SCHEMA,
input=PROJECT_UPDATE_SCHEMA)
def update(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
project.name = request.json.get("name", project.name)
project_path = request.json.get("path", project.path)
if project_path != project.path:
old_path = project.path
project.path = project_path
for module in MODULES:
yield from module.instance().project_moved(project)
response.json(project)
@Route.post( @Route.post(
r"/projects/{project_id}/close", r"/projects/{project_id}/close",
description="Close a project", description="Close a project",

View File

@ -30,6 +30,7 @@ from gns3server.config import Config
from gns3server.schemas.project import ( from gns3server.schemas.project import (
PROJECT_OBJECT_SCHEMA, PROJECT_OBJECT_SCHEMA,
PROJECT_UPDATE_SCHEMA,
PROJECT_LOAD_SCHEMA, PROJECT_LOAD_SCHEMA,
PROJECT_CREATE_SCHEMA PROJECT_CREATE_SCHEMA
) )
@ -83,6 +84,26 @@ class ProjectHandler:
project = controller.get_project(request.match_info["project_id"]) project = controller.get_project(request.match_info["project_id"])
response.json(project) response.json(project)
@Route.put(
r"/projects/{project_id}",
status_codes={
200: "Node updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Update a project instance",
input=PROJECT_UPDATE_SCHEMA,
output=PROJECT_OBJECT_SCHEMA)
def update(request, response):
project = Controller.instance().get_project(request.match_info["project_id"])
# Ignore these because we only use them when creating a project
request.json.pop("project_id", None)
yield from project.update(**request.json)
response.set_status(200)
response.json(project)
@Route.post( @Route.post(
r"/projects/{project_id}/close", r"/projects/{project_id}/close",
description="Close a project", description="Close a project",

View File

@ -62,6 +62,16 @@ def test_json(tmpdir):
assert p.__json__() == {"name": "Test", "project_id": p.id, "path": p.path, "status": "opened", "filename": "Test.gns3"} assert p.__json__() == {"name": "Test", "project_id": p.id, "path": p.path, "status": "opened", "filename": "Test.gns3"}
def test_update(controller, async_run):
project = Project(controller=controller, name="Hello")
controller._notification = MagicMock()
assert project.name == "Hello"
async_run(project.update(name="World"))
assert project.name == "World"
controller.notification.emit.assert_any_call("project.updated", project.__json__())
def test_path(tmpdir): def test_path(tmpdir):
directory = Config.instance().get_section_config("Server").get("projects_path") directory = Config.instance().get_section_config("Server").get("projects_path")

View File

@ -97,7 +97,6 @@ def test_restore(project, controller, async_run):
# project.closed notification should not be send when restoring snapshots # project.closed notification should not be send when restoring snapshots
assert "project.closed" not in [c[0][0] for c in controller.notification.emit.call_args_list] assert "project.closed" not in [c[0][0] for c in controller.notification.emit.call_args_list]
project = controller.get_project(project.id) project = controller.get_project(project.id)
assert not os.path.exists(test_file) assert not os.path.exists(test_file)
assert len(project.nodes) == 1 assert len(project.nodes) == 1

View File

@ -67,6 +67,18 @@ def test_create_project_with_uuid(http_controller):
assert response.json["name"] == "test" assert response.json["name"] == "test"
def test_update_project(http_controller):
query = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f"}
response = http_controller.post("/projects", query)
assert response.status == 201
assert response.json["project_id"] == "10010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json["name"] == "test"
query = {"name": "test2"}
response = http_controller.put("/projects/10010203-0405-0607-0809-0a0b0c0d0e0f", query, example=True)
assert response.status == 200
assert response.json["name"] == "test2"
def test_list_projects(http_controller, tmpdir): def test_list_projects(http_controller, tmpdir):
http_controller.post("/projects", {"name": "test", "path": str(tmpdir), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"}) http_controller.post("/projects", {"name": "test", "path": str(tmpdir), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"})
response = http_controller.get("/projects", example=True) response = http_controller.get("/projects", example=True)