From be4aa41dda1702c3552387c28b5c09d915bc9f59 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Fri, 11 Mar 2016 15:06:14 +0100 Subject: [PATCH] Create VPCS VM on controller --- gns3server/controller/hypervisor.py | 4 ++-- gns3server/controller/vm.py | 10 ++++---- .../handlers/api/controller/__init__.py | 1 - .../handlers/api/controller/vm_handler.py | 1 - gns3server/hypervisor/vpcs/vpcs_vm.py | 1 + gns3server/schemas/vm.py | 12 ++++++---- gns3server/schemas/vpcs.py | 14 ++++++++++- tests/controller/test_controller.py | 2 +- tests/controller/test_hypervisor.py | 10 ++++++++ tests/controller/test_project.py | 9 +++++-- tests/controller/test_vm.py | 8 +++++-- tests/handlers/api/controller/test_project.py | 14 +++++------ tests/handlers/api/controller/test_vm.py | 24 ++++++++++++------- 13 files changed, 76 insertions(+), 34 deletions(-) diff --git a/gns3server/controller/hypervisor.py b/gns3server/controller/hypervisor.py index 54bd8863..7304e4ea 100644 --- a/gns3server/controller/hypervisor.py +++ b/gns3server/controller/hypervisor.py @@ -90,9 +90,9 @@ class Hypervisor: data = data.__json__() data = json.dumps(data) response = yield from session.request(method, url, headers=headers, data=data) - print(response.status) - assert response.status < 300 body = yield from response.read() + if response.status >= 300: + raise aiohttp.errors.HttpProcessingError(code=response.status, message=body) yield from response.release() return body diff --git a/gns3server/controller/vm.py b/gns3server/controller/vm.py index a693fd2c..98413613 100644 --- a/gns3server/controller/vm.py +++ b/gns3server/controller/vm.py @@ -21,7 +21,8 @@ import uuid class VM: - def __init__(self, project, hypervisor, vm_id=None, vm_type=None, name=None, console=None, console_type="telnet", **kwargs): + + def __init__(self, project, hypervisor, vm_id=None, vm_type=None, name=None, console=None, console_type="telnet", properties={}): """ :param project: Project of the VM :param hypervisor: Hypervisor server where the server will run @@ -30,7 +31,7 @@ class VM: :param name: Name of the vm :param console: TCP port of the console :param console_type: Type of the console (telnet, vnc, serial..) - :param kwargs: Emulator specific properties of the VM + :param properties: Emulator specific properties of the VM """ if vm_id is None: @@ -44,7 +45,7 @@ class VM: self._vm_type = vm_type self._console = console self._console_type = console_type - self._properties = kwargs + self._properties = properties @property def id(self): @@ -74,6 +75,7 @@ class VM: def create(self): data = self._properties data["vm_id"] = self._id + data["name"] = self._name data["console"] = self._console data["console_type"] = self._console_type yield from self._hypervisor.post("/projects/{}/{}/vms".format(self._project.id, self._vm_type), data=data) @@ -81,6 +83,7 @@ class VM: def __json__(self): return { "hypervisor_id": self._hypervisor.id, + "project_id": self._project.id, "vm_id": self._id, "vm_type": self._vm_type, "name": self._name, @@ -88,4 +91,3 @@ class VM: "console_type": self._console_type, "properties": self._properties } - diff --git a/gns3server/handlers/api/controller/__init__.py b/gns3server/handlers/api/controller/__init__.py index 99ecd923..5eac84b5 100644 --- a/gns3server/handlers/api/controller/__init__.py +++ b/gns3server/handlers/api/controller/__init__.py @@ -19,4 +19,3 @@ from .hypervisor_handler import HypervisorHandler from .project_handler import ProjectHandler from .version_handler import VersionHandler from .vm_handler import VMHandler - diff --git a/gns3server/handlers/api/controller/vm_handler.py b/gns3server/handlers/api/controller/vm_handler.py index 75696d79..5ff6efb7 100644 --- a/gns3server/handlers/api/controller/vm_handler.py +++ b/gns3server/handlers/api/controller/vm_handler.py @@ -47,4 +47,3 @@ class VMHandler: vm = yield from project.addVM(hypervisor, request.json.pop("vm_id", None), **request.json) response.set_status(201) response.json(vm) - diff --git a/gns3server/hypervisor/vpcs/vpcs_vm.py b/gns3server/hypervisor/vpcs/vpcs_vm.py index 3e5bd3c0..36b499d2 100644 --- a/gns3server/hypervisor/vpcs/vpcs_vm.py +++ b/gns3server/hypervisor/vpcs/vpcs_vm.py @@ -112,6 +112,7 @@ class VPCSVM(BaseVM): "vm_directory": self.working_dir, "status": self.status, "console": self._console, + "console_type": "telnet", "project_id": self.project.id, "startup_script": self.startup_script, "startup_script_path": self.relative_startup_script, diff --git a/gns3server/schemas/vm.py b/gns3server/schemas/vm.py index 37b5133d..4c54b26f 100644 --- a/gns3server/schemas/vm.py +++ b/gns3server/schemas/vm.py @@ -70,15 +70,19 @@ VM_OBJECT_SCHEMA = { "type": "object", "properties": { "hypervisor_id": { - "description": "Server identifier", + "description": "Hypervisor identifier", + "type": "string" + }, + "project_id": { + "description": "Project identifier", "type": "string" }, "vm_id": { "description": "VM identifier", "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" + "minLength": 36, + "maxLength": 36, + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" }, "vm_type": { "description": "Type of VM", diff --git a/gns3server/schemas/vpcs.py b/gns3server/schemas/vpcs.py index bdaae578..90008f35 100644 --- a/gns3server/schemas/vpcs.py +++ b/gns3server/schemas/vpcs.py @@ -42,6 +42,10 @@ VPCS_CREATE_SCHEMA = { "maximum": 65535, "type": ["integer", "null"] }, + "console_type": { + "description": "console type", + "enum": ["telnet"] + }, "startup_script": { "description": "Content of the VPCS startup script", "type": ["string", "null"] @@ -67,6 +71,10 @@ VPCS_UPDATE_SCHEMA = { "maximum": 65535, "type": ["integer", "null"] }, + "console_type": { + "description": "console type", + "enum": ["telnet"] + }, "startup_script": { "description": "Content of the VPCS startup script", "type": ["string", "null"] @@ -106,6 +114,10 @@ VPCS_OBJECT_SCHEMA = { "maximum": 65535, "type": "integer" }, + "console_type": { + "description": "console type", + "enum": ["telnet"] + }, "project_id": { "description": "Project UUID", "type": "string", @@ -127,5 +139,5 @@ VPCS_OBJECT_SCHEMA = { } }, "additionalProperties": False, - "required": ["name", "vm_id", "status", "console", "project_id", "startup_script_path", "command_line"] + "required": ["name", "vm_id", "status", "console", "console_type", "project_id", "startup_script_path", "command_line"] } diff --git a/tests/controller/test_controller.py b/tests/controller/test_controller.py index 0a7660eb..7356ff63 100644 --- a/tests/controller/test_controller.py +++ b/tests/controller/test_controller.py @@ -79,7 +79,7 @@ def test_addProject_with_hypervisor(controller, async_run): hypervisor = Hypervisor("test1") hypervisor.post = MagicMock() - controller._hypervisors = {"test1": hypervisor } + controller._hypervisors = {"test1": hypervisor} project1 = async_run(controller.addProject(project_id=uuid1)) hypervisor.post.assert_called_with("/projects", project1) diff --git a/tests/controller/test_hypervisor.py b/tests/controller/test_hypervisor.py index 4512f975..845d5cb0 100644 --- a/tests/controller/test_hypervisor.py +++ b/tests/controller/test_hypervisor.py @@ -18,6 +18,7 @@ import pytest import json +import aiohttp from unittest.mock import patch, MagicMock from gns3server.controller.project import Project @@ -58,6 +59,15 @@ def test_hypervisor_httpQuery(hypervisor, async_run): mock.assert_called_with("POST", "https://example.com:84/v2/hypervisor/projects", data='{"a": "b"}', headers={'content-type': 'application/json'}) +def test_hypervisor_httpQueryError(hypervisor, async_run): + response = MagicMock() + with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: + response.status = 409 + + with pytest.raises(aiohttp.errors.HttpProcessingError): + async_run(hypervisor.post("/projects", {"a": "b"})) + + def test_hypervisor_httpQuery_project(hypervisor, async_run): response = MagicMock() with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: diff --git a/tests/controller/test_project.py b/tests/controller/test_project.py index 3c4d479b..7405ac93 100644 --- a/tests/controller/test_project.py +++ b/tests/controller/test_project.py @@ -38,5 +38,10 @@ def test_json(tmpdir): def test_addVM(async_run): hypervisor = MagicMock() project = Project() - vm = async_run(project.addVM(hypervisor, None, name="test", vm_type="vpcs", startup_config="test.cfg")) - hypervisor.post.assert_called_with('/projects/{}/vpcs/vms'.format(project.id), data={'console': None, 'vm_id': vm.id, 'console_type': 'telnet', 'startup_config': 'test.cfg'}) + vm = async_run(project.addVM(hypervisor, None, name="test", vm_type="vpcs", properties= {"startup_config": "test.cfg"})) + hypervisor.post.assert_called_with('/projects/{}/vpcs/vms'.format(project.id), + data={'console': None, + 'vm_id': vm.id, + 'console_type': 'telnet', + 'startup_config': 'test.cfg', + 'name': 'test'}) diff --git a/tests/controller/test_vm.py b/tests/controller/test_vm.py index 1639407c..6c7f2cfd 100644 --- a/tests/controller/test_vm.py +++ b/tests/controller/test_vm.py @@ -38,13 +38,15 @@ def vm(hypervisor): name="demo", vm_id=str(uuid.uuid4()), vm_type="vpcs", - console_type="vnc") + console_type="vnc", + properties={"startup_script": "echo test"}) return vm def test_json(vm, hypervisor): assert vm.__json__() == { "hypervisor_id": hypervisor.id, + "project_id": vm.project.id, "vm_id": vm.id, "vm_type": vm.vm_type, "name": "demo", @@ -66,6 +68,8 @@ def test_create(vm, hypervisor, project, async_run): data = { "console": None, "console_type": "vnc", - "vm_id": vm.id + "vm_id": vm.id, + "startup_script": "echo test", + "name": "demo" } hypervisor.post.assert_called_with("/projects/{}/vpcs/vms".format(vm.project.id), data=data) diff --git a/tests/handlers/api/controller/test_project.py b/tests/handlers/api/controller/test_project.py index e41d93f9..9e385e1e 100644 --- a/tests/handlers/api/controller/test_project.py +++ b/tests/handlers/api/controller/test_project.py @@ -1,13 +1,13 @@ # -*- 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, +# +# 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. diff --git a/tests/handlers/api/controller/test_vm.py b/tests/handlers/api/controller/test_vm.py index 414f391b..29797ebb 100644 --- a/tests/handlers/api/controller/test_vm.py +++ b/tests/handlers/api/controller/test_vm.py @@ -1,13 +1,13 @@ # -*- 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, +# +# 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. @@ -47,7 +47,13 @@ def project(http_controller, async_run): def test_create_vm(http_controller, tmpdir, project, hypervisor): - response = http_controller.post("/projects/{}/vms".format(project.id), {"name": "test", "vm_type": "vpcs", "hypervisor_id": "example.com"}, example=True) + response = http_controller.post("/projects/{}/vms".format(project.id), { + "name": "test", + "vm_type": "vpcs", + "hypervisor_id": "example.com", + "properties": { + "startup_script": "echo test" + } + }, example=True) assert response.status == 201 assert response.json["name"] == "test" -