diff --git a/docs/api/qemu.rst b/docs/api/qemu.rst
new file mode 100644
index 00000000..70fd8fc2
--- /dev/null
+++ b/docs/api/qemu.rst
@@ -0,0 +1,8 @@
+Qemu
+---------------------
+
+.. toctree::
+ :glob:
+ :maxdepth: 2
+
+ qemu/*
diff --git a/docs/api/qemu/v1projectsprojectidqemuvms.rst b/docs/api/qemu/v1projectsprojectidqemuvms.rst
new file mode 100644
index 00000000..4a88a237
--- /dev/null
+++ b/docs/api/qemu/v1projectsprojectidqemuvms.rst
@@ -0,0 +1,70 @@
+/v1/projects/{project_id}/qemu/vms
+----------------------------------------------------------------------------------------------------------------------
+
+.. contents::
+
+POST /v1/projects/**{project_id}**/qemu/vms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Create a new Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+
+Response status codes
+**********************
+- **400**: Invalid request
+- **201**: Instance created
+- **409**: Conflict
+
+Input
+*******
+.. raw:: html
+
+
+ Name | Mandatory | Type | Description |
+ adapter_type | | ['string', 'null'] | QEMU adapter type |
+ adapters | | ['integer', 'null'] | number of adapters |
+ console | | ['integer', 'null'] | console TCP port |
+ cpu_throttling | | ['integer', 'null'] | Percentage of CPU allowed for QEMU |
+ hda_disk_image | | ['string', 'null'] | QEMU hda disk image path |
+ hdb_disk_image | | ['string', 'null'] | QEMU hdb disk image path |
+ initrd | | ['string', 'null'] | QEMU initrd path |
+ kernel_command_line | | ['string', 'null'] | QEMU kernel command line |
+ kernel_image | | ['string', 'null'] | QEMU kernel image path |
+ legacy_networking | | ['boolean', 'null'] | Use QEMU legagy networking commands (-net syntax) |
+ monitor | | ['integer', 'null'] | monitor TCP port |
+ name | ✔ | string | QEMU VM instance name |
+ options | | ['string', 'null'] | Additional QEMU options |
+ process_priority | | enum | Possible values: realtime, very high, high, normal, low, very low, null |
+ qemu_path | ✔ | string | Path to QEMU |
+ ram | | ['integer', 'null'] | amount of RAM in MB |
+ vm_id | | ['string', 'null'] | QEMU VM UUID |
+
+
+Output
+*******
+.. raw:: html
+
+
+ Name | Mandatory | Type | Description |
+ adapter_type | ✔ | string | QEMU adapter type |
+ adapters | ✔ | integer | number of adapters |
+ console | ✔ | integer | console TCP port |
+ cpu_throttling | ✔ | integer | Percentage of CPU allowed for QEMU |
+ hda_disk_image | ✔ | string | QEMU hda disk image path |
+ hdb_disk_image | ✔ | string | QEMU hdb disk image path |
+ initrd | ✔ | string | QEMU initrd path |
+ kernel_command_line | ✔ | string | QEMU kernel command line |
+ kernel_image | ✔ | string | QEMU kernel image path |
+ legacy_networking | ✔ | boolean | Use QEMU legagy networking commands (-net syntax) |
+ monitor | ✔ | integer | monitor TCP port |
+ name | ✔ | string | QEMU VM instance name |
+ options | ✔ | string | Additional QEMU options |
+ process_priority | ✔ | enum | Possible values: realtime, very high, high, normal, low, very low |
+ project_id | ✔ | string | Project uuid |
+ qemu_path | ✔ | string | path to QEMU |
+ ram | ✔ | integer | amount of RAM in MB |
+ vm_id | ✔ | string | QEMU VM uuid |
+
+
diff --git a/docs/api/qemu/v1projectsprojectidqemuvmsvmid.rst b/docs/api/qemu/v1projectsprojectidqemuvmsvmid.rst
new file mode 100644
index 00000000..e90b3cfd
--- /dev/null
+++ b/docs/api/qemu/v1projectsprojectidqemuvmsvmid.rst
@@ -0,0 +1,129 @@
+/v1/projects/{project_id}/qemu/vms/{vm_id}
+----------------------------------------------------------------------------------------------------------------------
+
+.. contents::
+
+GET /v1/projects/**{project_id}**/qemu/vms/**{vm_id}**
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Get a Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+- **vm_id**: UUID for the instance
+
+Response status codes
+**********************
+- **200**: Success
+- **400**: Invalid request
+- **404**: Instance doesn't exist
+
+Output
+*******
+.. raw:: html
+
+
+ Name | Mandatory | Type | Description |
+ adapter_type | ✔ | string | QEMU adapter type |
+ adapters | ✔ | integer | number of adapters |
+ console | ✔ | integer | console TCP port |
+ cpu_throttling | ✔ | integer | Percentage of CPU allowed for QEMU |
+ hda_disk_image | ✔ | string | QEMU hda disk image path |
+ hdb_disk_image | ✔ | string | QEMU hdb disk image path |
+ initrd | ✔ | string | QEMU initrd path |
+ kernel_command_line | ✔ | string | QEMU kernel command line |
+ kernel_image | ✔ | string | QEMU kernel image path |
+ legacy_networking | ✔ | boolean | Use QEMU legagy networking commands (-net syntax) |
+ monitor | ✔ | integer | monitor TCP port |
+ name | ✔ | string | QEMU VM instance name |
+ options | ✔ | string | Additional QEMU options |
+ process_priority | ✔ | enum | Possible values: realtime, very high, high, normal, low, very low |
+ project_id | ✔ | string | Project uuid |
+ qemu_path | ✔ | string | path to QEMU |
+ ram | ✔ | integer | amount of RAM in MB |
+ vm_id | ✔ | string | QEMU VM uuid |
+
+
+
+PUT /v1/projects/**{project_id}**/qemu/vms/**{vm_id}**
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Update a Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+- **vm_id**: UUID for the instance
+
+Response status codes
+**********************
+- **200**: Instance updated
+- **400**: Invalid request
+- **404**: Instance doesn't exist
+- **409**: Conflict
+
+Input
+*******
+.. raw:: html
+
+
+ Name | Mandatory | Type | Description |
+ adapter_type | | ['string', 'null'] | QEMU adapter type |
+ adapters | | ['integer', 'null'] | number of adapters |
+ console | | ['integer', 'null'] | console TCP port |
+ cpu_throttling | | ['integer', 'null'] | Percentage of CPU allowed for QEMU |
+ hda_disk_image | | ['string', 'null'] | QEMU hda disk image path |
+ hdb_disk_image | | ['string', 'null'] | QEMU hdb disk image path |
+ initrd | | ['string', 'null'] | QEMU initrd path |
+ kernel_command_line | | ['string', 'null'] | QEMU kernel command line |
+ kernel_image | | ['string', 'null'] | QEMU kernel image path |
+ legacy_networking | | ['boolean', 'null'] | Use QEMU legagy networking commands (-net syntax) |
+ monitor | | ['integer', 'null'] | monitor TCP port |
+ name | | ['string', 'null'] | QEMU VM instance name |
+ options | | ['string', 'null'] | Additional QEMU options |
+ process_priority | | enum | Possible values: realtime, very high, high, normal, low, very low, null |
+ qemu_path | | ['string', 'null'] | Path to QEMU |
+ ram | | ['integer', 'null'] | amount of RAM in MB |
+
+
+Output
+*******
+.. raw:: html
+
+
+ Name | Mandatory | Type | Description |
+ adapter_type | ✔ | string | QEMU adapter type |
+ adapters | ✔ | integer | number of adapters |
+ console | ✔ | integer | console TCP port |
+ cpu_throttling | ✔ | integer | Percentage of CPU allowed for QEMU |
+ hda_disk_image | ✔ | string | QEMU hda disk image path |
+ hdb_disk_image | ✔ | string | QEMU hdb disk image path |
+ initrd | ✔ | string | QEMU initrd path |
+ kernel_command_line | ✔ | string | QEMU kernel command line |
+ kernel_image | ✔ | string | QEMU kernel image path |
+ legacy_networking | ✔ | boolean | Use QEMU legagy networking commands (-net syntax) |
+ monitor | ✔ | integer | monitor TCP port |
+ name | ✔ | string | QEMU VM instance name |
+ options | ✔ | string | Additional QEMU options |
+ process_priority | ✔ | enum | Possible values: realtime, very high, high, normal, low, very low |
+ project_id | ✔ | string | Project uuid |
+ qemu_path | ✔ | string | path to QEMU |
+ ram | ✔ | integer | amount of RAM in MB |
+ vm_id | ✔ | string | QEMU VM uuid |
+
+
+
+DELETE /v1/projects/**{project_id}**/qemu/vms/**{vm_id}**
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Delete a Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+- **vm_id**: UUID for the instance
+
+Response status codes
+**********************
+- **400**: Invalid request
+- **404**: Instance doesn't exist
+- **204**: Instance deleted
+
diff --git a/docs/api/qemu/v1projectsprojectidqemuvmsvmidadaptersadapternumberdportsportnumberdnio.rst b/docs/api/qemu/v1projectsprojectidqemuvmsvmidadaptersadapternumberdportsportnumberdnio.rst
new file mode 100644
index 00000000..8d0b3733
--- /dev/null
+++ b/docs/api/qemu/v1projectsprojectidqemuvmsvmidadaptersadapternumberdportsportnumberdnio.rst
@@ -0,0 +1,40 @@
+/v1/projects/{project_id}/qemu/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio
+----------------------------------------------------------------------------------------------------------------------
+
+.. contents::
+
+POST /v1/projects/**{project_id}**/qemu/vms/**{vm_id}**/adapters/**{adapter_number:\d+}**/ports/**{port_number:\d+}**/nio
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Add a NIO to a Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+- **vm_id**: UUID for the instance
+- **adapter_number**: Network adapter where the nio is located
+- **port_number**: Port where the nio should be added
+
+Response status codes
+**********************
+- **400**: Invalid request
+- **201**: NIO created
+- **404**: Instance doesn't exist
+
+
+DELETE /v1/projects/**{project_id}**/qemu/vms/**{vm_id}**/adapters/**{adapter_number:\d+}**/ports/**{port_number:\d+}**/nio
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Remove a NIO from a Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+- **vm_id**: UUID for the instance
+- **adapter_number**: Network adapter where the nio is located
+- **port_number**: Port from where the nio should be removed
+
+Response status codes
+**********************
+- **400**: Invalid request
+- **404**: Instance doesn't exist
+- **204**: NIO deleted
+
diff --git a/docs/api/qemu/v1projectsprojectidqemuvmsvmidreload.rst b/docs/api/qemu/v1projectsprojectidqemuvmsvmidreload.rst
new file mode 100644
index 00000000..04e239f6
--- /dev/null
+++ b/docs/api/qemu/v1projectsprojectidqemuvmsvmidreload.rst
@@ -0,0 +1,20 @@
+/v1/projects/{project_id}/qemu/vms/{vm_id}/reload
+----------------------------------------------------------------------------------------------------------------------
+
+.. contents::
+
+POST /v1/projects/**{project_id}**/qemu/vms/**{vm_id}**/reload
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Reload a Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+- **vm_id**: UUID for the instance
+
+Response status codes
+**********************
+- **400**: Invalid request
+- **404**: Instance doesn't exist
+- **204**: Instance reloaded
+
diff --git a/docs/api/qemu/v1projectsprojectidqemuvmsvmidstart.rst b/docs/api/qemu/v1projectsprojectidqemuvmsvmidstart.rst
new file mode 100644
index 00000000..d2649825
--- /dev/null
+++ b/docs/api/qemu/v1projectsprojectidqemuvmsvmidstart.rst
@@ -0,0 +1,20 @@
+/v1/projects/{project_id}/qemu/vms/{vm_id}/start
+----------------------------------------------------------------------------------------------------------------------
+
+.. contents::
+
+POST /v1/projects/**{project_id}**/qemu/vms/**{vm_id}**/start
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Start a Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+- **vm_id**: UUID for the instance
+
+Response status codes
+**********************
+- **400**: Invalid request
+- **404**: Instance doesn't exist
+- **204**: Instance started
+
diff --git a/docs/api/qemu/v1projectsprojectidqemuvmsvmidstop.rst b/docs/api/qemu/v1projectsprojectidqemuvmsvmidstop.rst
new file mode 100644
index 00000000..be132747
--- /dev/null
+++ b/docs/api/qemu/v1projectsprojectidqemuvmsvmidstop.rst
@@ -0,0 +1,20 @@
+/v1/projects/{project_id}/qemu/vms/{vm_id}/stop
+----------------------------------------------------------------------------------------------------------------------
+
+.. contents::
+
+POST /v1/projects/**{project_id}**/qemu/vms/**{vm_id}**/stop
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Stop a Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+- **vm_id**: UUID for the instance
+
+Response status codes
+**********************
+- **400**: Invalid request
+- **404**: Instance doesn't exist
+- **204**: Instance stopped
+
diff --git a/docs/api/qemu/v1projectsprojectidqemuvmsvmidsuspend.rst b/docs/api/qemu/v1projectsprojectidqemuvmsvmidsuspend.rst
new file mode 100644
index 00000000..c9da38a2
--- /dev/null
+++ b/docs/api/qemu/v1projectsprojectidqemuvmsvmidsuspend.rst
@@ -0,0 +1,20 @@
+/v1/projects/{project_id}/qemu/vms/{vm_id}/suspend
+----------------------------------------------------------------------------------------------------------------------
+
+.. contents::
+
+POST /v1/projects/**{project_id}**/qemu/vms/**{vm_id}**/suspend
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Reload a Qemu.instance
+
+Parameters
+**********
+- **project_id**: UUID for the project
+- **vm_id**: UUID for the instance
+
+Response status codes
+**********************
+- **400**: Invalid request
+- **404**: Instance doesn't exist
+- **204**: Instance suspended
+
diff --git a/gns3server/handlers/qemu_handler.py b/gns3server/handlers/qemu_handler.py
index 9ccbd237..11cdb928 100644
--- a/gns3server/handlers/qemu_handler.py
+++ b/gns3server/handlers/qemu_handler.py
@@ -24,6 +24,7 @@ from ..schemas.qemu import QEMU_CREATE_SCHEMA
from ..schemas.qemu import QEMU_UPDATE_SCHEMA
from ..schemas.qemu import QEMU_OBJECT_SCHEMA
from ..schemas.qemu import QEMU_NIO_SCHEMA
+from ..schemas.qemu import QEMU_BINARY_LIST_SCHEMA
from ..modules.qemu import Qemu
@@ -258,3 +259,22 @@ class QEMUHandler:
vm = qemu_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
vm.adapter_remove_nio_binding(int(request.match_info["adapter_number"]), int(request.match_info["port_number"]))
response.set_status(204)
+
+ @classmethod
+ @Route.get(
+ r"/projects/{project_id}/qemu/binaries",
+ parameters={
+ "project_id": "UUID for the project"
+ },
+ status_codes={
+ 200: "Success",
+ 400: "Invalid request",
+ 404: "Instance doesn't exist"
+ },
+ description="Get a list of available Qemu binaries",
+ output=QEMU_BINARY_LIST_SCHEMA)
+ def list_binaries(request, response):
+
+ qemu_manager = Qemu.instance()
+ binaries = yield from Qemu.binary_list()
+ response.json(binaries)
diff --git a/gns3server/modules/qemu/__init__.py b/gns3server/modules/qemu/__init__.py
index 58c87484..69abd613 100644
--- a/gns3server/modules/qemu/__init__.py
+++ b/gns3server/modules/qemu/__init__.py
@@ -20,7 +20,12 @@ Qemu server module.
"""
import asyncio
+import os
+import sys
+import re
+import subprocess
+from ...utils.asyncio import subprocess_check_output
from ..base_manager import BaseManager
from .qemu_error import QemuError
from .qemu_vm import QemuVM
@@ -38,4 +43,68 @@ class Qemu(BaseManager):
:returns: working directory name
"""
- return "pc-{}".format(legacy_vm_id)
+ return "vm-{}".format(legacy_vm_id)
+
+ @staticmethod
+ def binary_list():
+ """
+ Gets QEMU binaries list available on the matchine
+
+ :returns: Array of dictionnary {"path": Qemu binaries path, "version": Version of Qemu}
+ """
+
+ qemus = []
+ paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep)
+ # look for Qemu binaries in the current working directory and $PATH
+ if sys.platform.startswith("win"):
+ # add specific Windows paths
+ if hasattr(sys, "frozen"):
+ # add any qemu dir in the same location as gns3server.exe to the list of paths
+ exec_dir = os.path.dirname(os.path.abspath(sys.executable))
+ for f in os.listdir(exec_dir):
+ if f.lower().startswith("qemu"):
+ paths.append(os.path.join(exec_dir, f))
+
+ if "PROGRAMFILES(X86)" in os.environ and os.path.exists(os.environ["PROGRAMFILES(X86)"]):
+ paths.append(os.path.join(os.environ["PROGRAMFILES(X86)"], "qemu"))
+ if "PROGRAMFILES" in os.environ and os.path.exists(os.environ["PROGRAMFILES"]):
+ paths.append(os.path.join(os.environ["PROGRAMFILES"], "qemu"))
+ elif sys.platform.startswith("darwin"):
+ # add specific locations on Mac OS X regardless of what's in $PATH
+ paths.extend(["/usr/local/bin", "/opt/local/bin"])
+ if hasattr(sys, "frozen"):
+ paths.append(os.path.abspath(os.path.join(os.getcwd(), "../../../qemu/bin/")))
+ for path in paths:
+ try:
+ for f in os.listdir(path):
+ if (f.startswith("qemu-system") or f == "qemu" or f == "qemu.exe") and \
+ os.access(os.path.join(path, f), os.X_OK) and \
+ os.path.isfile(os.path.join(path, f)):
+ 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:
+ continue
+
+ return qemus
+
+ @staticmethod
+ @asyncio.coroutine
+ def _get_qemu_version(qemu_path):
+ """
+ Gets the Qemu version.
+ :param qemu_path: path to Qemu
+ """
+
+ if sys.platform.startswith("win"):
+ return ""
+ try:
+ output = yield from subprocess_check_output(qemu_path, "-version")
+ match = re.search("version\s+([0-9a-z\-\.]+)", output.decode("utf-8"))
+ if match:
+ version = match.group(1)
+ return version
+ else:
+ raise QemuError("Could not determine the Qemu version for {}".format(qemu_path))
+ except subprocess.SubprocessError as e:
+ raise QemuError("Error while looking for the Qemu version: {}".format(e))
diff --git a/gns3server/schemas/qemu.py b/gns3server/schemas/qemu.py
index 065f4a73..5c55c00d 100644
--- a/gns3server/schemas/qemu.py
+++ b/gns3server/schemas/qemu.py
@@ -361,3 +361,28 @@ QEMU_OBJECT_SCHEMA = {
"legacy_networking", "cpu_throttling", "process_priority", "options"
]
}
+
+QEMU_BINARY_LIST_SCHEMA = {
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "description": "Request validation for a list of qemu binaries",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/QemuPath"
+ },
+ "definitions": {
+ "QemuPath": {
+ "description": "Qemu path object",
+ "properties": {
+ "path": {
+ "description": "Qemu path",
+ "type": "string",
+ },
+ "version": {
+ "description": "Qemu version",
+ "type": "string",
+ },
+ },
+ }
+ },
+ "additionalProperties": False,
+}
diff --git a/tests/api/test_qemu.py b/tests/api/test_qemu.py
index 9e62fd73..6d184b27 100644
--- a/tests/api/test_qemu.py
+++ b/tests/api/test_qemu.py
@@ -155,3 +155,13 @@ def test_qemu_delete_nio(server, vm):
response = server.delete("/projects/{project_id}/qemu/vms/{vm_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), example=True)
assert response.status == 204
assert response.route == "/projects/{project_id}/qemu/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
+
+
+def test_qemu_list_binaries(server, vm):
+ ret = [{"path": "/tmp/1", "version": "2.2.0"},
+ {"path": "/tmp/2", "version": "2.1.0"}]
+ with asyncio_patch("gns3server.modules.qemu.Qemu.binary_list", return_value=ret) as mock:
+ response = server.get("/projects/{project_id}/qemu/binaries".format(project_id=vm["project_id"]))
+ assert mock.called
+ assert response.status == 200
+ assert response.json == ret
diff --git a/tests/modules/qemu/test_qemu_manager.py b/tests/modules/qemu/test_qemu_manager.py
new file mode 100644
index 00000000..9309f6da
--- /dev/null
+++ b/tests/modules/qemu/test_qemu_manager.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015 GNS3 Technologies Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import os
+import stat
+import asyncio
+
+from gns3server.modules.qemu import Qemu
+from tests.utils import asyncio_patch
+
+
+def test_get_qemu_version(loop):
+
+ with asyncio_patch("gns3server.modules.qemu.subprocess_check_output", return_value=b"QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard") as mock:
+ version = loop.run_until_complete(asyncio.async(Qemu._get_qemu_version("/tmp/qemu-test")))
+ assert version == "2.2.0"
+
+
+def test_binary_list(loop):
+
+ files_to_create = ["qemu-system-x86", "qemu-system-x42", "hello"]
+
+ for file_to_create in files_to_create:
+ path = os.path.join(os.environ["PATH"], file_to_create)
+ with open(path, "w+") as f:
+ f.write("1")
+ os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
+
+ with asyncio_patch("gns3server.modules.qemu.subprocess_check_output", return_value=b"QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard") as mock:
+ qemus = loop.run_until_complete(asyncio.async(Qemu.binary_list()))
+
+ assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": "2.2.0"} in qemus
+ assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x42"), "version": "2.2.0"} in qemus
+ assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": "2.2.0"} not in qemus
+
+
+def test_get_legacy_vm_workdir_name():
+
+ assert Qemu.get_legacy_vm_workdir_name(42) == "vm-42"