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:
parent
28308b10bc
commit
f97c2b2cbe
@ -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)
|
||||||
|
@ -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):
|
||||||
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user