1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-12-24 15:58:08 +00:00

HTTP api start iou process

Now we need to start ioucon
This commit is contained in:
Julien Duponchelle 2015-02-11 15:37:05 +01:00
parent 2e99ef69a9
commit 986c63f344
5 changed files with 433 additions and 28 deletions

View File

@ -3,4 +3,5 @@ __all__ = ["version_handler",
"vpcs_handler",
"project_handler",
"virtualbox_handler",
"dynamips_handler"]
"dynamips_handler",
"iou_handler"]

View File

@ -0,0 +1,180 @@
# -*- 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 <http://www.gnu.org/licenses/>.
from ..web.route import Route
from ..schemas.iou import IOU_CREATE_SCHEMA
from ..schemas.iou import IOU_UPDATE_SCHEMA
from ..schemas.iou import IOU_OBJECT_SCHEMA
from ..modules.iou import IOU
class IOUHandler:
"""
API entry points for IOU.
"""
@classmethod
@Route.post(
r"/projects/{project_id}/iou/vms",
parameters={
"project_id": "UUID for the project"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new IOU instance",
input=IOU_CREATE_SCHEMA,
output=IOU_OBJECT_SCHEMA)
def create(request, response):
iou = IOU.instance()
vm = yield from iou.create_vm(request.json["name"],
request.match_info["project_id"],
request.json.get("vm_id"),
console=request.json.get("console"),
)
vm.iou_path = request.json.get("iou_path", vm.iou_path)
vm.iourc_path = request.json.get("iourc_path", vm.iourc_path)
response.set_status(201)
response.json(vm)
@classmethod
@Route.get(
r"/projects/{project_id}/iou/vms/{vm_id}",
parameters={
"project_id": "UUID for the project",
"vm_id": "UUID for the instance"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a IOU instance",
output=IOU_OBJECT_SCHEMA)
def show(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
response.json(vm)
@classmethod
@Route.put(
r"/projects/{project_id}/iou/vms/{vm_id}",
parameters={
"project_id": "UUID for the project",
"vm_id": "UUID for the instance"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a IOU instance",
input=IOU_UPDATE_SCHEMA,
output=IOU_OBJECT_SCHEMA)
def update(request, response):
iou_manager = IOU.instance()
vm = iou_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.iou_path = request.json.get("iou_path", vm.iou_path)
vm.iourc_path = request.json.get("iourc_path", vm.iourc_path)
response.json(vm)
@classmethod
@Route.delete(
r"/projects/{project_id}/iou/vms/{vm_id}",
parameters={
"project_id": "UUID for the project",
"vm_id": "UUID for the instance"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a IOU instance")
def delete(request, response):
yield from IOU.instance().delete_vm(request.match_info["vm_id"])
response.set_status(204)
@classmethod
@Route.post(
r"/projects/{project_id}/iou/vms/{vm_id}/start",
parameters={
"project_id": "UUID for the project",
"vm_id": "UUID for the instance"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a IOU instance")
def start(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
yield from vm.start()
response.set_status(204)
@classmethod
@Route.post(
r"/projects/{project_id}/iou/vms/{vm_id}/stop",
parameters={
"project_id": "UUID for the project",
"vm_id": "UUID for the instance"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a IOU instance")
def stop(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
yield from vm.stop()
response.set_status(204)
@classmethod
@Route.post(
r"/projects/{project_id}/iou/vms/{vm_id}/reload",
parameters={
"project_id": "UUID for the project",
"vm_id": "UUID for the instance",
},
status_codes={
204: "Instance reloaded",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Reload a IOU instance")
def reload(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
yield from vm.reload()
response.set_status(204)

View File

@ -63,7 +63,7 @@ class IOUVM(BaseVM):
self._iou_stdout_file = ""
self._started = False
self._iou_path = None
self._iourc = None
self._iourc_path = None
self._ioucon_thread = None
# IOU settings
@ -124,13 +124,24 @@ class IOUVM(BaseVM):
raise IOUError("IOU image '{}' is not executable".format(self._iou_path))
@property
def iourc(self):
def iourc_path(self):
"""
Returns the path to the iourc file.
:returns: path to the iourc file
"""
return self._iourc
return self._iourc_path
@iourc_path.setter
def iourc_path(self, path):
"""
Set path to IOURC file
"""
self._iourc_path = path
log.info("IOU {name} [id={id}]: iourc file path set to {path}".format(name=self._name,
id=self._id,
path=self._iourc_path))
@property
def use_default_iou_values(self):
@ -154,18 +165,6 @@ class IOUVM(BaseVM):
else:
log.info("IOU {name} [id={id}]: does not use the default IOU image values".format(name=self._name, id=self._id))
@iourc.setter
def iourc(self, iourc):
"""
Sets the path to the iourc file.
:param iourc: path to the iourc file.
"""
self._iourc = iourc
log.info("IOU {name} [id={id}]: iourc file path set to {path}".format(name=self._name,
id=self._id,
path=self._iourc))
def _check_requirements(self):
"""
Check if IOUYAP is available
@ -186,6 +185,8 @@ class IOUVM(BaseVM):
"vm_id": self.id,
"console": self._console,
"project_id": self.project.id,
"iourc_path": self._iourc_path,
"iou_path": self.iou_path
}
@property
@ -229,7 +230,7 @@ class IOUVM(BaseVM):
def application_id(self):
return self._manager.get_application_id(self.id)
#TODO: ASYNCIO
# TODO: ASYNCIO
def _library_check(self):
"""
Checks for missing shared library dependencies in the IOU image.
@ -257,9 +258,9 @@ class IOUVM(BaseVM):
if not self.is_running():
# TODO: ASYNC
#self._library_check()
# self._library_check()
if not self._iourc or not os.path.isfile(self._iourc):
if not self._iourc_path or not os.path.isfile(self._iourc_path):
raise IOUError("A valid iourc file is necessary to start IOU")
iouyap_path = self.iouyap_path
@ -269,18 +270,18 @@ class IOUVM(BaseVM):
self._create_netmap_config()
# created a environment variable pointing to the iourc file.
env = os.environ.copy()
env["IOURC"] = self._iourc
env["IOURC"] = self._iourc_path
self._command = self._build_command()
try:
log.info("Starting IOU: {}".format(self._command))
self._iou_stdout_file = os.path.join(self.working_dir, "iou.log")
log.info("Logging to {}".format(self._iou_stdout_file))
with open(self._iou_stdout_file, "w") as fd:
self._iou_process = yield from asyncio.create_subprocess_exec(self._command,
stdout=fd,
stderr=subprocess.STDOUT,
cwd=self.working_dir,
env=env)
self._iou_process = yield from asyncio.create_subprocess_exec(*self._command,
stdout=fd,
stderr=subprocess.STDOUT,
cwd=self.working_dir,
env=env)
log.info("IOU instance {} started PID={}".format(self._id, self._iou_process.pid))
self._started = True
except FileNotFoundError as e:
@ -291,10 +292,9 @@ class IOUVM(BaseVM):
raise IOUError("could not start IOU {}: {}\n{}".format(self._iou_path, e, iou_stdout))
# start console support
#self._start_ioucon()
# self._start_ioucon()
# connections support
#self._start_iouyap()
# self._start_iouyap()
@asyncio.coroutine
def stop(self):

127
gns3server/schemas/iou.py Normal file
View File

@ -0,0 +1,127 @@
# -*- 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 <http://www.gnu.org/licenses/>.
IOU_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new IOU instance",
"type": "object",
"properties": {
"name": {
"description": "IOU VM name",
"type": "string",
"minLength": 1,
},
"vm_id": {
"description": "IOU VM identifier",
"oneOf": [
{"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}$"},
{"type": "integer"} # for legacy projects
]
},
"console": {
"description": "console TCP port",
"minimum": 1,
"maximum": 65535,
"type": ["integer", "null"]
},
"iou_path": {
"description": "Path of iou binary",
"type": "string"
},
"iourc_path": {
"description": "Path of iourc",
"type": "string"
},
},
"additionalProperties": False,
"required": ["name", "iou_path", "iourc_path"]
}
IOU_UPDATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to update a IOU instance",
"type": "object",
"properties": {
"name": {
"description": "IOU VM name",
"type": ["string", "null"],
"minLength": 1,
},
"console": {
"description": "console TCP port",
"minimum": 1,
"maximum": 65535,
"type": ["integer", "null"]
},
"iou_path": {
"description": "Path of iou binary",
"type": "string"
},
"iourc_path": {
"description": "Path of iourc",
"type": "string"
},
},
"additionalProperties": False,
}
IOU_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "IOU instance",
"type": "object",
"properties": {
"name": {
"description": "IOU VM name",
"type": "string",
"minLength": 1,
},
"vm_id": {
"description": "IOU VM UUID",
"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}$"
},
"console": {
"description": "console TCP port",
"minimum": 1,
"maximum": 65535,
"type": "integer"
},
"project_id": {
"description": "Project UUID",
"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}$"
},
"iou_path": {
"description": "Path of iou binary",
"type": "string"
},
"iourc_path": {
"description": "Path of iourc",
"type": "string"
},
},
"additionalProperties": False,
"required": ["name", "vm_id", "console", "project_id", "iou_path", "iourc_path"]
}

97
tests/api/test_iou.py Normal file
View File

@ -0,0 +1,97 @@
# -*- 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 <http://www.gnu.org/licenses/>.
import pytest
import os
import stat
from tests.utils import asyncio_patch
from unittest.mock import patch
@pytest.fixture
def fake_iou_bin(tmpdir):
"""Create a fake IOU image on disk"""
path = str(tmpdir / "iou.bin")
with open(path, "w+") as f:
f.write('\x7fELF\x01\x01\x01')
os.chmod(path, stat.S_IREAD | stat.S_IEXEC)
return path
@pytest.fixture
def base_params(tmpdir, fake_iou_bin):
"""Return standard parameters"""
return {"name": "PC TEST 1", "iou_path": fake_iou_bin, "iourc_path": str(tmpdir / "iourc")}
@pytest.fixture
def vm(server, project, base_params):
response = server.post("/projects/{project_id}/iou/vms".format(project_id=project.id), base_params)
assert response.status == 201
return response.json
def test_iou_create(server, project, base_params):
response = server.post("/projects/{project_id}/iou/vms".format(project_id=project.id), base_params, example=True)
assert response.status == 201
assert response.route == "/projects/{project_id}/iou/vms"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
def test_iou_get(server, project, vm):
response = server.get("/projects/{project_id}/iou/vms/{vm_id}".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), example=True)
assert response.status == 200
assert response.route == "/projects/{project_id}/iou/vms/{vm_id}"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
def test_iou_start(server, vm):
with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM.start", return_value=True) as mock:
response = server.post("/projects/{project_id}/iou/vms/{vm_id}/start".format(project_id=vm["project_id"], vm_id=vm["vm_id"]))
assert mock.called
assert response.status == 204
def test_iou_stop(server, vm):
with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM.stop", return_value=True) as mock:
response = server.post("/projects/{project_id}/iou/vms/{vm_id}/stop".format(project_id=vm["project_id"], vm_id=vm["vm_id"]))
assert mock.called
assert response.status == 204
def test_iou_reload(server, vm):
with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM.reload", return_value=True) as mock:
response = server.post("/projects/{project_id}/iou/vms/{vm_id}/reload".format(project_id=vm["project_id"], vm_id=vm["vm_id"]))
assert mock.called
assert response.status == 204
def test_iou_delete(server, vm):
with asyncio_patch("gns3server.modules.iou.IOU.delete_vm", return_value=True) as mock:
response = server.delete("/projects/{project_id}/iou/vms/{vm_id}".format(project_id=vm["project_id"], vm_id=vm["vm_id"]))
assert mock.called
assert response.status == 204
def test_iou_update(server, vm, tmpdir, free_console_port):
response = server.put("/projects/{project_id}/iou/vms/{vm_id}".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), {"name": "test",
"console": free_console_port})
assert response.status == 200
assert response.json["name"] == "test"
assert response.json["console"] == free_console_port