Adds a handler for getting the Qemu related capabilities of the server. Currently includes just a check for KVM architectures.

This commit is contained in:
Vasil Rangelov 2016-01-01 02:40:12 +02:00
parent 38622c4da3
commit d00efbfb0f
4 changed files with 99 additions and 7 deletions

View File

@ -25,7 +25,9 @@ from ...schemas.nio import NIO_SCHEMA
from ...schemas.qemu import QEMU_CREATE_SCHEMA from ...schemas.qemu import QEMU_CREATE_SCHEMA
from ...schemas.qemu import QEMU_UPDATE_SCHEMA from ...schemas.qemu import QEMU_UPDATE_SCHEMA
from ...schemas.qemu import QEMU_OBJECT_SCHEMA from ...schemas.qemu import QEMU_OBJECT_SCHEMA
from ...schemas.qemu import QEMU_BINARY_FILTER_SCHEMA
from ...schemas.qemu import QEMU_BINARY_LIST_SCHEMA from ...schemas.qemu import QEMU_BINARY_LIST_SCHEMA
from ...schemas.qemu import QEMU_CAPABILITY_LIST_SCHEMA
from ...schemas.qemu import QEMU_IMAGE_CREATE_SCHEMA from ...schemas.qemu import QEMU_IMAGE_CREATE_SCHEMA
from ...schemas.vm import VM_LIST_IMAGES_SCHEMA from ...schemas.vm import VM_LIST_IMAGES_SCHEMA
from ...modules.qemu import Qemu from ...modules.qemu import Qemu
@ -300,10 +302,11 @@ class QEMUHandler:
404: "Instance doesn't exist" 404: "Instance doesn't exist"
}, },
description="Get a list of available Qemu binaries", description="Get a list of available Qemu binaries",
input=QEMU_BINARY_FILTER_SCHEMA,
output=QEMU_BINARY_LIST_SCHEMA) output=QEMU_BINARY_LIST_SCHEMA)
def list_binaries(request, response): def list_binaries(request, response):
binaries = yield from Qemu.binary_list() binaries = yield from Qemu.binary_list(request.json["archs"] if "archs" in request.json else None)
response.json(binaries) response.json(binaries)
@classmethod @classmethod
@ -321,6 +324,21 @@ class QEMUHandler:
binaries = yield from Qemu.img_binary_list() binaries = yield from Qemu.img_binary_list()
response.json(binaries) response.json(binaries)
@Route.get(
r"/qemu/capabilities",
status_codes={
200: "Success"
},
description="Get a list of Qemu capabilities on this server",
output=QEMU_CAPABILITY_LIST_SCHEMA
)
def get_capabilities(request, response):
capabilities = {}
kvms = Qemu.get_kvm_archs()
if kvms:
capabilities["kvm"] = kvms
response.json(capabilities)
@classmethod @classmethod
@Route.post( @Route.post(
r"/qemu/img", r"/qemu/img",

View File

@ -21,6 +21,7 @@ Qemu server module.
import asyncio import asyncio
import os import os
import platform
import sys import sys
import re import re
import subprocess import subprocess
@ -38,6 +39,27 @@ class Qemu(BaseManager):
_VM_CLASS = QemuVM _VM_CLASS = QemuVM
@staticmethod
def get_kvm_archs():
"""
Gets a list of architectures for which KVM is available on this server.
:returns: List of architectures for which KVM is available on this server.
"""
kvm = []
x86_64_aliases = ["x86_64", "x86-64", "x64", "AMD64", "amd64", "Intel 64", "EM64T"]
i386_aliases = ["i386", "x86", "x32"]
if sys.platform.startswith("linux") and subprocess.call("kvm-ok") == 0:
arch = platform.machine()
if arch in x86_64_aliases:
kvm.append("x86_64")
kvm.append("i386")
elif arch in i386_aliases:
kvm.append("i386")
else:
kvm.append(platform.machine())
return kvm
@staticmethod @staticmethod
def paths_list(): def paths_list():
""" """
@ -82,7 +104,7 @@ class Qemu(BaseManager):
return paths return paths
@staticmethod @staticmethod
def binary_list(): def binary_list(archs=None):
""" """
Gets QEMU binaries list available on the host. Gets QEMU binaries list available on the host.
@ -96,9 +118,17 @@ class Qemu(BaseManager):
if (f.startswith("qemu-system") or f.startswith("qemu-kvm") or f == "qemu" or f == "qemu.exe") and \ if (f.startswith("qemu-system") or f.startswith("qemu-kvm") or f == "qemu" or f == "qemu.exe") and \
os.access(os.path.join(path, f), os.X_OK) and \ os.access(os.path.join(path, f), os.X_OK) and \
os.path.isfile(os.path.join(path, f)): os.path.isfile(os.path.join(path, f)):
qemu_path = os.path.join(path, f) if archs is not None:
version = yield from Qemu.get_qemu_version(qemu_path) for arch in archs:
qemus.append({"path": qemu_path, "version": version}) if f.endswith(arch) or f.endswith("{}.exe".format(arch)) or f.endswith("{}w.exe".format(arch)):
qemu_path = os.path.join(path, f)
version = yield from Qemu.get_qemu_version(qemu_path)
qemus.append({"path": qemu_path, "version": version})
else:
qemu_path = os.path.join(path, f)
version = yield from Qemu.get_qemu_version(qemu_path)
qemus.append({"path": qemu_path, "version": version})
except OSError: except OSError:
continue continue

View File

@ -601,6 +601,21 @@ QEMU_OBJECT_SCHEMA = {
"vm_directory"] "vm_directory"]
} }
QEMU_BINARY_FILTER_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation for a list of qemu capabilities",
"properties": {
"archs": {
"description": "Architectures to filter binaries by",
"type": "array",
"items": {
"enum": QEMU_PLATFORMS
}
}
},
"additionalProperties": False,
}
QEMU_BINARY_LIST_SCHEMA = { QEMU_BINARY_LIST_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation for a list of qemu binaries", "description": "Request validation for a list of qemu binaries",
@ -626,6 +641,21 @@ QEMU_BINARY_LIST_SCHEMA = {
"additionalProperties": False, "additionalProperties": False,
} }
QEMU_CAPABILITY_LIST_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation for a list of qemu capabilities",
"properties": {
"kvm": {
"description": "Architectures that KVM is enabled for",
"type": "array",
"items": {
"enum": QEMU_PLATFORMS
}
}
},
"additionalProperties": False,
}
QEMU_IMAGE_CREATE_SCHEMA = { QEMU_IMAGE_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"description": "Create a new qemu image. Options can be specific to a format. Read qemu-img manual for more information", "description": "Create a new qemu image. Options can be specific to a format. Read qemu-img manual for more information",

View File

@ -58,18 +58,32 @@ def test_binary_list(loop):
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
with asyncio_patch("gns3server.modules.qemu.subprocess_check_output", return_value="QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard") as mock: with asyncio_patch("gns3server.modules.qemu.subprocess_check_output", return_value="QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard") as mock:
qemus = loop.run_until_complete(asyncio.async(Qemu.binary_list()))
if sys.platform.startswith("win"): if sys.platform.startswith("win"):
version = "" version = ""
else: else:
version = "2.2.0" version = "2.2.0"
qemus = loop.run_until_complete(asyncio.async(Qemu.binary_list()))
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} in qemus assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x42"), "version": version} in qemus assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x42"), "version": version} in qemus
assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus
qemus = loop.run_until_complete(asyncio.async(Qemu.binary_list(["x86"])))
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} not in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x42"), "version": version} not in qemus
assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus
qemus = loop.run_until_complete(asyncio.async(Qemu.binary_list(["x86", "x42"])))
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} not in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x42"), "version": version} in qemus
assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus
def test_img_binary_list(loop): def test_img_binary_list(loop):