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

Delete a VM, mark it as destroyable

This commit is contained in:
Julien Duponchelle 2015-01-23 11:28:58 +01:00
parent 28308b10bc
commit f97c2b2cbe
6 changed files with 105 additions and 11 deletions

View File

@ -30,9 +30,28 @@ class ProjectHandler:
output=PROJECT_OBJECT_SCHEMA, output=PROJECT_OBJECT_SCHEMA,
input=PROJECT_OBJECT_SCHEMA) input=PROJECT_OBJECT_SCHEMA)
def create_project(request, response): def create_project(request, response):
pm = ProjectManager.instance() pm = ProjectManager.instance()
p = pm.create_project( p = pm.create_project(
location=request.json.get("location"), location=request.json.get("location"),
uuid=request.json.get("uuid") uuid=request.json.get("uuid")
) )
response.json(p) response.json(p)
@classmethod
@Route.post(
r"/project/{uuid}/commit",
description="Write changes on disk",
parameters={
"uuid": "Project instance UUID",
},
status_codes={
204: "Changes write on disk",
404: "Project instance doesn't exist"
})
def create_project(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["uuid"])
project.commit()
response.set_status(204)

View File

@ -149,14 +149,13 @@ class BaseManager:
self._vms[vm.uuid] = vm self._vms[vm.uuid] = vm
return vm return vm
# FIXME: should be named close_vm and we should have a
# delete_vm when a user deletes a VM (including files in workdir)
@asyncio.coroutine @asyncio.coroutine
def delete_vm(self, uuid): def close_vm(self, uuid):
""" """
Delete a VM Delete a VM
:param uuid: VM UUID :param uuid: VM UUID
:returns: VM instance
""" """
vm = self.get_vm(uuid) vm = self.get_vm(uuid)
@ -164,7 +163,22 @@ class BaseManager:
yield from vm.close() yield from vm.close()
else: else:
vm.close() vm.close()
return vm
@asyncio.coroutine
def delete_vm(self, uuid):
"""
Delete a VM. VM working directory will be destroy when
we receive a commit.
:param uuid: VM UUID
:returns: VM instance
"""
vm = yield from self.close_vm(uuid)
vm.project.mark_vm_for_destruction(vm)
del self._vms[vm.uuid] del self._vms[vm.uuid]
return vm
@staticmethod @staticmethod
def _has_privileged_access(executable): def _has_privileged_access(executable):

View File

@ -96,7 +96,7 @@ class BaseVM:
Return VM working directory Return VM working directory
""" """
return self._project.vm_working_directory(self.manager.module_name.lower(), self._uuid) return self._project.vm_working_directory(self)
def create(self): def create(self):
""" """

View File

@ -18,6 +18,7 @@
import aiohttp import aiohttp
import os import os
import tempfile import tempfile
import shutil
from uuid import UUID, uuid4 from uuid import UUID, uuid4
@ -45,6 +46,7 @@ class Project:
if location is None: if location is None:
self._location = tempfile.mkdtemp() self._location = tempfile.mkdtemp()
self._vms_to_destroy = set()
self._path = os.path.join(self._location, self._uuid) self._path = os.path.join(self._location, self._uuid)
try: try:
os.makedirs(os.path.join(self._path, "vms"), exist_ok=True) os.makedirs(os.path.join(self._path, "vms"), exist_ok=True)
@ -66,25 +68,40 @@ class Project:
return self._path return self._path
def vm_working_directory(self, module, vm_uuid): def vm_working_directory(self, vm):
""" """
Return a working directory for a specific VM. Return a working directory for a specific VM.
If the directory doesn't exist, the directory is created. If the directory doesn't exist, the directory is created.
:param module: The module name (vpcs, dynamips...) :param vm: An instance of VM
:param vm_uuid: VM UUID :returns: A string with a VM working directory
""" """
workdir = os.path.join(self._path, module, vm_uuid) workdir = os.path.join(self._path, vm.manager.module_name.lower(), vm.uuid)
try: try:
os.makedirs(workdir, exist_ok=True) os.makedirs(workdir, exist_ok=True)
except OSError as e: except OSError as e:
raise aiohttp.web.HTTPInternalServerError(text="Could not create VM working directory: {}".format(e)) raise aiohttp.web.HTTPInternalServerError(text="Could not create VM working directory: {}".format(e))
return workdir return workdir
def mark_vm_for_destruction(self, vm):
"""
:param vm: An instance of VM
"""
self._vms_to_destroy.add(vm)
def __json__(self): def __json__(self):
return { return {
"uuid": self._uuid, "uuid": self._uuid,
"location": self._location "location": self._location
} }
def commit(self):
"""Write project changes on disk"""
while self._vms_to_destroy:
vm = self._vms_to_destroy.pop()
directory = self.vm_working_directory(vm)
if os.path.exists(directory):
shutil.rmtree(directory)

View File

@ -19,6 +19,8 @@
This test suite check /project endpoint This test suite check /project endpoint
""" """
import uuid
def test_create_project_with_dir(server, tmpdir): def test_create_project_with_dir(server, tmpdir):
response = server.post("/project", {"location": str(tmpdir)}) response = server.post("/project", {"location": str(tmpdir)})
@ -46,3 +48,13 @@ def test_create_project_with_uuid(server):
assert response.status == 200 assert response.status == 200
assert response.json["uuid"] == "00010203-0405-0607-0809-0a0b0c0d0e0f" assert response.json["uuid"] == "00010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json["location"] == "/tmp" assert response.json["location"] == "/tmp"
def test_commit_project(server, project):
response = server.post("/project/{uuid}/commit".format(uuid=project.uuid))
assert response.status == 204
def test_commit_project_invalid_project_uuid(server, project):
response = server.post("/project/{uuid}/commit".format(uuid=uuid.uuid4()))
assert response.status == 404

View File

@ -17,7 +17,21 @@
# 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 os import os
import pytest
from gns3server.modules.project import Project from gns3server.modules.project import Project
from gns3server.modules.vpcs import VPCS, VPCSVM
@pytest.fixture(scope="module")
def manager(port_manager):
m = VPCS.instance()
m.port_manager = port_manager
return m
@pytest.fixture(scope="function")
def vm(project, manager):
return VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def test_affect_uuid(): def test_affect_uuid():
@ -45,7 +59,25 @@ def test_json(tmpdir):
assert p.__json__() == {"location": p.location, "uuid": p.uuid} assert p.__json__() == {"location": p.location, "uuid": p.uuid}
def test_vm_working_directory(tmpdir): def test_vm_working_directory(tmpdir, vm):
p = Project(location=str(tmpdir)) p = Project(location=str(tmpdir))
assert os.path.exists(p.vm_working_directory('vpcs', '00010203-0405-0607-0809-0a0b0c0d0e0f')) assert os.path.exists(p.vm_working_directory(vm))
assert os.path.exists(os.path.join(str(tmpdir), p.uuid, 'vpcs', '00010203-0405-0607-0809-0a0b0c0d0e0f')) assert os.path.exists(os.path.join(str(tmpdir), p.uuid, vm.module_name, vm.uuid))
def test_mark_vm_for_destruction(tmpdir, vm):
p = Project(location=str(tmpdir))
p.mark_vm_for_destruction(vm)
assert len(p._vms_to_destroy) == 1
def test_commit(tmpdir, manager):
project = Project(location=str(tmpdir))
vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
directory = project.vm_working_directory(vm)
project.mark_vm_for_destruction(vm)
assert len(project._vms_to_destroy) == 1
assert os.path.exists(directory)
project.commit()
assert len(project._vms_to_destroy) == 0
assert os.path.exists(directory) is False