From 48f5c7c8b30aae982e6e539542a15b8200cdfb72 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Thu, 19 Feb 2015 20:22:30 +0100 Subject: [PATCH] All params for qemu --- gns3server/handlers/qemu_handler.py | 12 +- gns3server/modules/qemu/qemu_vm.py | 13 +- gns3server/schemas/qemu.py | 183 ++++++++++++++++------------ tests/api/test_qemu.py | 28 ++--- tests/modules/qemu/test_qemu_vm.py | 7 ++ 5 files changed, 139 insertions(+), 104 deletions(-) diff --git a/gns3server/handlers/qemu_handler.py b/gns3server/handlers/qemu_handler.py index a40bfd78..9ccbd237 100644 --- a/gns3server/handlers/qemu_handler.py +++ b/gns3server/handlers/qemu_handler.py @@ -59,6 +59,13 @@ class QEMUHandler: console_host=PortManager.instance().console_host, monitor_host=PortManager.instance().console_host, ) + # Clear already used keys + map(request.json.__delitem__, ["name", "project_id", "vm_id", + "qemu_path", "console", "monitor"]) + + for field in request.json: + setattr(vm, field, request.json[field]) + response.set_status(201) response.json(vm) @@ -102,9 +109,8 @@ class QEMUHandler: qemu_manager = Qemu.instance() vm = qemu_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) - vm.name = request.json.get("name", vm.name) - vm.console = request.json.get("console", vm.console) - vm.qemu_path = request.json.get("qemu_path", vm.qemu_path) + for field in request.json: + setattr(vm, field, request.json[field]) response.json(vm) diff --git a/gns3server/modules/qemu/qemu_vm.py b/gns3server/modules/qemu/qemu_vm.py index 01b36e47..23ddf018 100644 --- a/gns3server/modules/qemu/qemu_vm.py +++ b/gns3server/modules/qemu/qemu_vm.py @@ -38,6 +38,7 @@ from ..adapters.ethernet_adapter import EthernetAdapter from ..nios.nio_udp import NIO_UDP from ..base_vm import BaseVM from ...utils.asyncio import subprocess_check_output +from ...schemas.qemu import QEMU_OBJECT_SCHEMA import logging log = logging.getLogger(__name__) @@ -973,10 +974,12 @@ class QemuVM(BaseVM): return command def __json__(self): - return { - "vm_id": self.id, + answer = { "project_id": self.project.id, - "name": self.name, - "console": self.console, - "monitor": self.monitor + "vm_id": self.id } + # Qemu has a long list of options. The JSON schema is the single source of informations + for field in QEMU_OBJECT_SCHEMA["required"]: + if field not in answer: + answer[field] = getattr(self, field) + return answer diff --git a/gns3server/schemas/qemu.py b/gns3server/schemas/qemu.py index bbd2aabf..065f4a73 100644 --- a/gns3server/schemas/qemu.py +++ b/gns3server/schemas/qemu.py @@ -21,6 +21,11 @@ QEMU_CREATE_SCHEMA = { "description": "Request validation to create a new QEMU VM instance", "type": "object", "properties": { + "vm_id": { + "description": "QEMU VM UUID", + "type": ["string", "null"], + "minLength": 1, + }, "name": { "description": "QEMU VM instance name", "type": "string", @@ -35,13 +40,72 @@ QEMU_CREATE_SCHEMA = { "description": "console TCP port", "minimum": 1, "maximum": 65535, - "type": "integer" + "type": ["integer", "null"] }, "monitor": { "description": "monitor TCP port", "minimum": 1, "maximum": 65535, - "type": "integer" + "type": ["integer", "null"] + }, + "hda_disk_image": { + "description": "QEMU hda disk image path", + "type": ["string", "null"], + }, + "hdb_disk_image": { + "description": "QEMU hdb disk image path", + "type": ["string", "null"], + }, + "ram": { + "description": "amount of RAM in MB", + "type": ["integer", "null"] + }, + "adapters": { + "description": "number of adapters", + "type": ["integer", "null"], + "minimum": 0, + "maximum": 32, + }, + "adapter_type": { + "description": "QEMU adapter type", + "type": ["string", "null"], + "minLength": 1, + }, + "initrd": { + "description": "QEMU initrd path", + "type": ["string", "null"], + }, + "kernel_image": { + "description": "QEMU kernel image path", + "type": ["string", "null"], + }, + "kernel_command_line": { + "description": "QEMU kernel command line", + "type": ["string", "null"], + }, + "legacy_networking": { + "description": "Use QEMU legagy networking commands (-net syntax)", + "type": ["boolean", "null"], + }, + "cpu_throttling": { + "description": "Percentage of CPU allowed for QEMU", + "minimum": 0, + "maximum": 800, + "type": ["integer", "null"], + }, + "process_priority": { + "description": "Process priority for QEMU", + "enum": ["realtime", + "very high", + "high", + "normal", + "low", + "very low", + "null"] + }, + "options": { + "description": "Additional QEMU options", + "type": ["string", "null"], }, }, "additionalProperties": False, @@ -55,74 +119,70 @@ QEMU_UPDATE_SCHEMA = { "properties": { "name": { "description": "QEMU VM instance name", - "type": "string", + "type": ["string", "null"], "minLength": 1, }, "qemu_path": { - "description": "path to QEMU", - "type": "string", - "minLength": 1, - }, - "hda_disk_image": { - "description": "QEMU hda disk image path", - "type": "string", - }, - "hdb_disk_image": { - "description": "QEMU hdb disk image path", - "type": "string", - }, - "ram": { - "description": "amount of RAM in MB", - "type": "integer" - }, - "adapters": { - "description": "number of adapters", - "type": "integer", - "minimum": 0, - "maximum": 32, - }, - "adapter_type": { - "description": "QEMU adapter type", - "type": "string", + "description": "Path to QEMU", + "type": ["string", "null"], "minLength": 1, }, "console": { "description": "console TCP port", "minimum": 1, "maximum": 65535, - "type": "integer" + "type": ["integer", "null"] }, "monitor": { "description": "monitor TCP port", "minimum": 1, "maximum": 65535, - "type": "integer" + "type": ["integer", "null"] + }, + "hda_disk_image": { + "description": "QEMU hda disk image path", + "type": ["string", "null"], + }, + "hdb_disk_image": { + "description": "QEMU hdb disk image path", + "type": ["string", "null"], + }, + "ram": { + "description": "amount of RAM in MB", + "type": ["integer", "null"] + }, + "adapters": { + "description": "number of adapters", + "type": ["integer", "null"], + "minimum": 0, + "maximum": 32, + }, + "adapter_type": { + "description": "QEMU adapter type", + "type": ["string", "null"], + "minLength": 1, }, "initrd": { "description": "QEMU initrd path", - "type": "string", + "type": ["string", "null"], }, "kernel_image": { "description": "QEMU kernel image path", - "type": "string", + "type": ["string", "null"], }, "kernel_command_line": { "description": "QEMU kernel command line", - "type": "string", - }, - "cloud_path": { - "description": "Path to the image in the cloud object store", - "type": "string", + "type": ["string", "null"], }, "legacy_networking": { "description": "Use QEMU legagy networking commands (-net syntax)", - "type": "boolean", + "type": ["boolean", "null"], }, "cpu_throttling": { "description": "Percentage of CPU allowed for QEMU", "minimum": 0, "maximum": 800, - "type": "integer", + "type": ["integer", "null"], }, "process_priority": { "description": "Process priority for QEMU", @@ -131,30 +191,17 @@ QEMU_UPDATE_SCHEMA = { "high", "normal", "low", - "very low"] + "very low", + "null"] }, "options": { "description": "Additional QEMU options", - "type": "string", + "type": ["string", "null"], }, }, "additionalProperties": False, } -QEMU_START_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to start a QEMU VM instance", - "type": "object", - "properties": { - "id": { - "description": "QEMU VM instance ID", - "type": "integer" - }, - }, - "additionalProperties": False, - "required": ["id"] -} - QEMU_NIO_SCHEMA = { "$schema": "http://json-schema.org/draft-04/schema#", "description": "Request validation to add a NIO for a VPCS instance", @@ -202,26 +249,10 @@ QEMU_NIO_SCHEMA = { "required": ["type", "ethernet_device"], "additionalProperties": False }, - "TAP": { - "description": "TAP Network Input/Output", - "properties": { - "type": { - "enum": ["nio_tap"] - }, - "tap_device": { - "description": "TAP device name e.g. tap0", - "type": "string", - "minLength": 1 - }, - }, - "required": ["type", "tap_device"], - "additionalProperties": False - }, }, "oneOf": [ {"$ref": "#/definitions/UDP"}, {"$ref": "#/definitions/Ethernet"}, - {"$ref": "#/definitions/TAP"}, ], "additionalProperties": True, "required": ["type"] @@ -299,10 +330,6 @@ QEMU_OBJECT_SCHEMA = { "description": "QEMU kernel command line", "type": "string", }, - "cloud_path": { - "description": "Path to the image in the cloud object store", - "type": "string", - }, "legacy_networking": { "description": "Use QEMU legagy networking commands (-net syntax)", "type": "boolean", @@ -328,5 +355,9 @@ QEMU_OBJECT_SCHEMA = { }, }, "additionalProperties": False, - "required": ["vm_id"] + "required": ["vm_id", "project_id", "name", "qemu_path", "hda_disk_image", + "hdb_disk_image", "ram", "adapters", "adapter_type", "console", + "monitor", "initrd", "kernel_image", "kernel_command_line", + "legacy_networking", "cpu_throttling", "process_priority", "options" + ] } diff --git a/tests/api/test_qemu.py b/tests/api/test_qemu.py index 25cc9f9b..9e62fd73 100644 --- a/tests/api/test_qemu.py +++ b/tests/api/test_qemu.py @@ -55,12 +55,16 @@ def test_qemu_create(server, project, base_params): def test_qemu_create_with_params(server, project, base_params): params = base_params + params["ram"] = 1024 + params["hda_disk_image"] = "hda" response = server.post("/projects/{project_id}/qemu/vms".format(project_id=project.id), params, example=True) assert response.status == 201 assert response.route == "/projects/{project_id}/qemu/vms" assert response.json["name"] == "PC TEST 1" assert response.json["project_id"] == project.id + assert response.json["ram"] == 1024 + assert response.json["hda_disk_image"] == "hda" def test_qemu_get(server, project, vm): @@ -110,11 +114,15 @@ def test_qemu_update(server, vm, tmpdir, free_console_port, project): params = { "name": "test", "console": free_console_port, + "ram": 1024, + "hdb_disk_image": "hdb" } response = server.put("/projects/{project_id}/qemu/vms/{vm_id}".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), params) assert response.status == 200 assert response.json["name"] == "test" assert response.json["console"] == free_console_port + assert response.json["hdb_disk_image"] == "hdb" + assert response.json["ram"] == 1024 def test_qemu_nio_create_udp(server, vm): @@ -139,26 +147,6 @@ def test_qemu_nio_create_ethernet(server, vm): assert response.json["ethernet_device"] == "eth0" -def test_qemu_nio_create_ethernet_different_port(server, vm): - response = server.post("/projects/{project_id}/qemu/vms/{vm_id}/adapters/0/ports/3/nio".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), {"type": "nio_generic_ethernet", - "ethernet_device": "eth0", - }, - example=False) - assert response.status == 201 - assert response.route == "/projects/{project_id}/qemu/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio" - assert response.json["type"] == "nio_generic_ethernet" - assert response.json["ethernet_device"] == "eth0" - - -def test_qemu_nio_create_tap(server, vm): - with patch("gns3server.modules.base_manager.BaseManager._has_privileged_access", return_value=True): - response = server.post("/projects/{project_id}/qemu/vms/{vm_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), {"type": "nio_tap", - "tap_device": "test"}) - assert response.status == 201 - assert response.route == "/projects/{project_id}/qemu/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio" - assert response.json["type"] == "nio_tap" - - def test_qemu_delete_nio(server, vm): server.post("/projects/{project_id}/qemu/vms/{vm_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), {"type": "nio_udp", "lport": 4242, diff --git a/tests/modules/qemu/test_qemu_vm.py b/tests/modules/qemu/test_qemu_vm.py index 63b89572..1a59acca 100644 --- a/tests/modules/qemu/test_qemu_vm.py +++ b/tests/modules/qemu/test_qemu_vm.py @@ -196,3 +196,10 @@ def test_set_process_priority(vm, loop, fake_qemu_img_binary): assert process.called args, kwargs = process.call_args assert args == ("renice", "-n", "5", "-p", "42") + + +def test_json(vm, project): + + json = vm.__json__() + assert json["name"] == vm.name + assert json["project_id"] == project.id