mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-24 09:18:08 +00:00
Handlers: cleanup and fixes.
This commit is contained in:
parent
885d93be02
commit
f81d35cc29
@ -22,7 +22,6 @@ Docker server module.
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import urllib
|
|
||||||
import json
|
import json
|
||||||
from gns3server.utils import parse_version
|
from gns3server.utils import parse_version
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ class VirtualBox(BaseManager):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def list_images(self):
|
def list_vms(self):
|
||||||
"""
|
"""
|
||||||
Gets VirtualBox VM list.
|
Gets VirtualBox VM list.
|
||||||
"""
|
"""
|
||||||
|
@ -31,7 +31,7 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class Controller:
|
class Controller:
|
||||||
"""The controller manage multiple gns3 computes"""
|
"""The controller manage multiple gns3 compute servers"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._computes = {}
|
self._computes = {}
|
||||||
@ -97,7 +97,7 @@ class Controller:
|
|||||||
|
|
||||||
# We disallow to create from the outside the
|
# We disallow to create from the outside the
|
||||||
if compute_id == 'local':
|
if compute_id == 'local':
|
||||||
return self._createLocalCompute()
|
return self._create_local_compute()
|
||||||
|
|
||||||
if compute_id not in self._computes:
|
if compute_id not in self._computes:
|
||||||
compute = Compute(compute_id=compute_id, controller=self, **kwargs)
|
compute = Compute(compute_id=compute_id, controller=self, **kwargs)
|
||||||
@ -105,7 +105,7 @@ class Controller:
|
|||||||
self.save()
|
self.save()
|
||||||
return self._computes[compute_id]
|
return self._computes[compute_id]
|
||||||
|
|
||||||
def _createLocalCompute(self):
|
def _create_local_compute(self):
|
||||||
"""
|
"""
|
||||||
Create the local compute node. It's the controller itself
|
Create the local compute node. It's the controller itself
|
||||||
"""
|
"""
|
||||||
@ -139,7 +139,7 @@ class Controller:
|
|||||||
raise aiohttp.web.HTTPNotFound(text="Compute ID {} doesn't exist".format(compute_id))
|
raise aiohttp.web.HTTPNotFound(text="Compute ID {} doesn't exist".format(compute_id))
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def addProject(self, project_id=None, **kwargs):
|
def add_project(self, project_id=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Create a project or return an existing project
|
Create a project or return an existing project
|
||||||
|
|
||||||
|
@ -17,16 +17,15 @@
|
|||||||
|
|
||||||
from aiohttp.web import HTTPForbidden
|
from aiohttp.web import HTTPForbidden
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....config import Config
|
from gns3server.config import Config
|
||||||
|
|
||||||
|
|
||||||
class ConfigHandler:
|
class ConfigHandler:
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/config/reload",
|
r"/config/reload",
|
||||||
description="Check if version is the same as the server",
|
description="Reload the server configuration file",
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Config reload",
|
201: "Config reload",
|
||||||
403: "Config reload refused"
|
403: "Config reload refused"
|
||||||
@ -35,6 +34,6 @@ class ConfigHandler:
|
|||||||
|
|
||||||
config = Config.instance()
|
config = Config.instance()
|
||||||
if config.get_section_config("Server").getboolean("local", False) is False:
|
if config.get_section_config("Server").getboolean("local", False) is False:
|
||||||
raise HTTPForbidden(text="You can only reload the configuration for a local server")
|
raise HTTPForbidden(text="The configuration can only be reloaded on a local server")
|
||||||
config.reload()
|
config.reload()
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
|
@ -18,40 +18,26 @@
|
|||||||
import os
|
import os
|
||||||
from aiohttp.web import HTTPConflict
|
from aiohttp.web import HTTPConflict
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....compute.docker import Docker
|
from gns3server.compute.docker import Docker
|
||||||
|
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
|
||||||
|
from gns3server.schemas.nio import NIO_SCHEMA
|
||||||
|
|
||||||
from ....schemas.docker import (
|
from gns3server.schemas.docker import (
|
||||||
DOCKER_CREATE_SCHEMA,
|
DOCKER_CREATE_SCHEMA,
|
||||||
DOCKER_OBJECT_SCHEMA,
|
DOCKER_OBJECT_SCHEMA,
|
||||||
DOCKER_UPDATE_SCHEMA,
|
DOCKER_UPDATE_SCHEMA,
|
||||||
DOCKER_LIST_IMAGES_SCHEMA
|
DOCKER_LIST_IMAGES_SCHEMA
|
||||||
)
|
)
|
||||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
|
||||||
from ....schemas.nio import NIO_SCHEMA
|
|
||||||
|
|
||||||
|
|
||||||
class DockerHandler:
|
class DockerHandler:
|
||||||
"""API entry points for Docker."""
|
"""API entry points for Docker containers."""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
|
||||||
r"/docker/images",
|
|
||||||
status_codes={
|
|
||||||
200: "Success",
|
|
||||||
},
|
|
||||||
output=DOCKER_LIST_IMAGES_SCHEMA,
|
|
||||||
description="Get all available Docker images")
|
|
||||||
def show(request, response):
|
|
||||||
docker_manager = Docker.instance()
|
|
||||||
images = yield from docker_manager.list_images()
|
|
||||||
response.json(images)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/docker/nodes",
|
r"/projects/{project_id}/docker/nodes",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
201: "Instance created",
|
||||||
@ -63,33 +49,32 @@ class DockerHandler:
|
|||||||
output=DOCKER_OBJECT_SCHEMA)
|
output=DOCKER_OBJECT_SCHEMA)
|
||||||
def create(request, response):
|
def create(request, response):
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = yield from docker_manager.create_node(request.json.pop("name"),
|
container = yield from docker_manager.create_node(request.json.pop("name"),
|
||||||
request.match_info["project_id"],
|
request.match_info["project_id"],
|
||||||
request.json.get("node_id"),
|
request.json.get("node_id"),
|
||||||
image=request.json.pop("image"),
|
image=request.json.pop("image"),
|
||||||
start_command=request.json.get("start_command"),
|
start_command=request.json.get("start_command"),
|
||||||
environment=request.json.get("environment"),
|
environment=request.json.get("environment"),
|
||||||
adapters=request.json.get("adapters"),
|
adapters=request.json.get("adapters"),
|
||||||
console=request.json.get("console"),
|
console=request.json.get("console"),
|
||||||
console_type=request.json.get("console_type"),
|
console_type=request.json.get("console_type"),
|
||||||
console_resolution=request.json.get("console_resolution", "1024x768"),
|
console_resolution=request.json.get("console_resolution", "1024x768"),
|
||||||
console_http_port=request.json.get("console_http_port", 80),
|
console_http_port=request.json.get("console_http_port", 80),
|
||||||
console_http_path=request.json.get("console_http_path", "/"),
|
console_http_path=request.json.get("console_http_path", "/"),
|
||||||
aux=request.json.get("aux"))
|
aux=request.json.get("aux"))
|
||||||
for name, value in request.json.items():
|
for name, value in request.json.items():
|
||||||
if name != "_node_id":
|
if name != "node_id":
|
||||||
if hasattr(vm, name) and getattr(vm, name) != value:
|
if hasattr(container, name) and getattr(container, name) != value:
|
||||||
setattr(vm, name, value)
|
setattr(container, name, value)
|
||||||
|
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(vm)
|
response.json(container)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}/start",
|
r"/projects/{project_id}/docker/nodes/{node_id}/start",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID of the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "ID of the container"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance started",
|
204: "Instance started",
|
||||||
@ -101,16 +86,15 @@ class DockerHandler:
|
|||||||
output=DOCKER_OBJECT_SCHEMA)
|
output=DOCKER_OBJECT_SCHEMA)
|
||||||
def start(request, response):
|
def start(request, response):
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
yield from vm.start()
|
yield from container.start()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}/stop",
|
r"/projects/{project_id}/docker/nodes/{node_id}/stop",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID of the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "ID of the container"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance stopped",
|
204: "Instance stopped",
|
||||||
@ -122,16 +106,15 @@ class DockerHandler:
|
|||||||
output=DOCKER_OBJECT_SCHEMA)
|
output=DOCKER_OBJECT_SCHEMA)
|
||||||
def stop(request, response):
|
def stop(request, response):
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
yield from vm.stop()
|
yield from container.stop()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}/reload",
|
r"/projects/{project_id}/docker/nodes/{node_id}/reload",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID of the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "ID of the container"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance restarted",
|
204: "Instance restarted",
|
||||||
@ -143,16 +126,15 @@ class DockerHandler:
|
|||||||
output=DOCKER_OBJECT_SCHEMA)
|
output=DOCKER_OBJECT_SCHEMA)
|
||||||
def reload(request, response):
|
def reload(request, response):
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
yield from vm.restart()
|
yield from container.restart()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}",
|
r"/projects/{project_id}/docker/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "ID for the container",
|
"node_id": "Node UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance deleted",
|
204: "Instance deleted",
|
||||||
@ -162,16 +144,15 @@ class DockerHandler:
|
|||||||
description="Delete a Docker container")
|
description="Delete a Docker container")
|
||||||
def delete(request, response):
|
def delete(request, response):
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
yield from vm.delete()
|
yield from container.delete()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}/suspend",
|
r"/projects/{project_id}/docker/nodes/{node_id}/pause",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID of the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "ID of the container"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance paused",
|
204: "Instance paused",
|
||||||
@ -181,17 +162,37 @@ class DockerHandler:
|
|||||||
description="Pause a Docker container",
|
description="Pause a Docker container",
|
||||||
input=DOCKER_CREATE_SCHEMA,
|
input=DOCKER_CREATE_SCHEMA,
|
||||||
output=DOCKER_OBJECT_SCHEMA)
|
output=DOCKER_OBJECT_SCHEMA)
|
||||||
def suspend(request, response):
|
def pause(request, response):
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
yield from vm.pause()
|
yield from container.pause()
|
||||||
|
response.set_status(204)
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/docker/nodes/{node_id}/unpause",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID"
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Instance unpaused",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
|
},
|
||||||
|
description="Unpause a Docker container",
|
||||||
|
input=DOCKER_CREATE_SCHEMA,
|
||||||
|
output=DOCKER_OBJECT_SCHEMA)
|
||||||
|
def unpause(request, response):
|
||||||
|
docker_manager = Docker.instance()
|
||||||
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
|
yield from container.unpause()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "ID of the container",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter where the nio should be added",
|
"adapter_number": "Adapter where the nio should be added",
|
||||||
"port_number": "Port on the adapter"
|
"port_number": "Port on the adapter"
|
||||||
},
|
},
|
||||||
@ -205,21 +206,20 @@ class DockerHandler:
|
|||||||
output=NIO_SCHEMA)
|
output=NIO_SCHEMA)
|
||||||
def create_nio(request, response):
|
def create_nio(request, response):
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
nio_type = request.json["type"]
|
nio_type = request.json["type"]
|
||||||
if nio_type not in ("nio_udp"):
|
if nio_type != "nio_udp":
|
||||||
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||||
nio = docker_manager.create_nio(int(request.match_info["adapter_number"]), request.json)
|
nio = docker_manager.create_nio(int(request.match_info["adapter_number"]), request.json)
|
||||||
yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
|
yield from container.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(nio)
|
response.json(nio)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "ID of the container",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter where the nio should be added",
|
"adapter_number": "Adapter where the nio should be added",
|
||||||
"port_number": "Port on the adapter"
|
"port_number": "Port on the adapter"
|
||||||
},
|
},
|
||||||
@ -231,16 +231,15 @@ class DockerHandler:
|
|||||||
description="Remove a NIO from a Docker container")
|
description="Remove a NIO from a Docker container")
|
||||||
def delete_nio(request, response):
|
def delete_nio(request, response):
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
yield from vm.adapter_remove_nio_binding(int(request.match_info["adapter_number"]))
|
yield from container.adapter_remove_nio_binding(int(request.match_info["adapter_number"]))
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}",
|
r"/projects/{project_id}/docker/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance updated",
|
200: "Instance updated",
|
||||||
@ -254,25 +253,25 @@ class DockerHandler:
|
|||||||
def update(request, response):
|
def update(request, response):
|
||||||
|
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
vm.name = request.json.get("name", vm.name)
|
container.name = request.json.get("name", container.name)
|
||||||
vm.console = request.json.get("console", vm.console)
|
container.console = request.json.get("console", container.console)
|
||||||
vm.aux = request.json.get("aux", vm.aux)
|
container.aux = request.json.get("aux", container.aux)
|
||||||
vm.console_type = request.json.get("console_type", vm.console_type)
|
container.console_type = request.json.get("console_type", container.console_type)
|
||||||
vm.console_resolution = request.json.get("console_resolution", vm.console_resolution)
|
container.console_resolution = request.json.get("console_resolution", container.console_resolution)
|
||||||
vm.console_http_port = request.json.get("console_http_port", vm.console_http_port)
|
container.console_http_port = request.json.get("console_http_port", container.console_http_port)
|
||||||
vm.console_http_path = request.json.get("console_http_path", vm.console_http_path)
|
container.console_http_path = request.json.get("console_http_path", container.console_http_path)
|
||||||
vm.start_command = request.json.get("start_command", vm.start_command)
|
container.start_command = request.json.get("start_command", container.start_command)
|
||||||
vm.environment = request.json.get("environment", vm.environment)
|
container.environment = request.json.get("environment", container.environment)
|
||||||
vm.adapters = request.json.get("adapters", vm.adapters)
|
container.adapters = request.json.get("adapters", container.adapters)
|
||||||
yield from vm.update()
|
yield from container.update()
|
||||||
response.json(vm)
|
response.json(container)
|
||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to start a packet capture",
|
"adapter_number": "Adapter to start a packet capture",
|
||||||
"port_number": "Port on the adapter"
|
"port_number": "Port on the adapter"
|
||||||
},
|
},
|
||||||
@ -282,25 +281,25 @@ class DockerHandler:
|
|||||||
404: "Instance doesn't exist",
|
404: "Instance doesn't exist",
|
||||||
409: "Node not started"
|
409: "Node not started"
|
||||||
},
|
},
|
||||||
description="Start a packet capture on a Docker VM instance",
|
description="Start a packet capture on a Docker container instance",
|
||||||
input=NODE_CAPTURE_SCHEMA)
|
input=NODE_CAPTURE_SCHEMA)
|
||||||
def start_capture(request, response):
|
def start_capture(request, response):
|
||||||
|
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
adapter_number = int(request.match_info["adapter_number"])
|
adapter_number = int(request.match_info["adapter_number"])
|
||||||
pcap_file_path = os.path.join(vm.project.capture_working_directory(), request.json["capture_file_name"])
|
pcap_file_path = os.path.join(container.project.capture_working_directory(), request.json["capture_file_name"])
|
||||||
|
|
||||||
if not vm.is_running():
|
if not container.is_running():
|
||||||
raise HTTPConflict(text="Cannot capture traffic on a non started VM")
|
raise HTTPConflict(text="Cannot capture traffic on a non started Docker container")
|
||||||
yield from vm.start_capture(adapter_number, pcap_file_path)
|
yield from container.start_capture(adapter_number, pcap_file_path)
|
||||||
response.json({"pcap_file_path": str(pcap_file_path)})
|
response.json({"pcap_file_path": str(pcap_file_path)})
|
||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to stop a packet capture",
|
"adapter_number": "Adapter to stop a packet capture",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -308,17 +307,29 @@ class DockerHandler:
|
|||||||
204: "Capture stopped",
|
204: "Capture stopped",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
404: "Instance doesn't exist",
|
404: "Instance doesn't exist",
|
||||||
409: "VM not started"
|
409: "Container not started"
|
||||||
},
|
},
|
||||||
description="Stop a packet capture on a IOU VM instance")
|
description="Stop a packet capture on a Docker container instance")
|
||||||
def stop_capture(request, response):
|
def stop_capture(request, response):
|
||||||
|
|
||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
|
|
||||||
if not vm.is_running():
|
if not container.is_running():
|
||||||
raise HTTPConflict(text="Cannot capture traffic on a non started VM")
|
raise HTTPConflict(text="Cannot capture traffic on a non started Docker container")
|
||||||
|
|
||||||
adapter_number = int(request.match_info["adapter_number"])
|
adapter_number = int(request.match_info["adapter_number"])
|
||||||
yield from vm.stop_capture(adapter_number)
|
yield from container.stop_capture(adapter_number)
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
|
@Route.get(
|
||||||
|
r"/docker/images",
|
||||||
|
status_codes={
|
||||||
|
200: "Success",
|
||||||
|
},
|
||||||
|
output=DOCKER_LIST_IMAGES_SCHEMA,
|
||||||
|
description="Get all available Docker images")
|
||||||
|
def show(request, response):
|
||||||
|
docker_manager = Docker.instance()
|
||||||
|
images = yield from docker_manager.list_images()
|
||||||
|
response.json(images)
|
||||||
|
@ -17,13 +17,17 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import asyncio
|
import asyncio
|
||||||
from ....web.route import Route
|
|
||||||
from ....schemas.dynamips_device import DEVICE_CREATE_SCHEMA
|
from gns3server.web.route import Route
|
||||||
from ....schemas.dynamips_device import DEVICE_UPDATE_SCHEMA
|
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
|
||||||
from ....schemas.dynamips_device import DEVICE_OBJECT_SCHEMA
|
from gns3server.compute.dynamips import Dynamips
|
||||||
from ....schemas.dynamips_device import DEVICE_NIO_SCHEMA
|
|
||||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
from gns3server.schemas.dynamips_device import (
|
||||||
from ....compute.dynamips import Dynamips
|
DEVICE_CREATE_SCHEMA,
|
||||||
|
DEVICE_UPDATE_SCHEMA,
|
||||||
|
DEVICE_OBJECT_SCHEMA,
|
||||||
|
DEVICE_NIO_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DynamipsDeviceHandler:
|
class DynamipsDeviceHandler:
|
||||||
@ -32,11 +36,10 @@ class DynamipsDeviceHandler:
|
|||||||
API entry points for Dynamips devices.
|
API entry points for Dynamips devices.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/devices",
|
r"/projects/{project_id}/dynamips/devices",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
201: "Instance created",
|
||||||
@ -57,12 +60,11 @@ class DynamipsDeviceHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(device)
|
response.json(device)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/dynamips/devices/{device_id}",
|
r"/projects/{project_id}/dynamips/devices/{device_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"device_id": "UUID for the instance"
|
"device_id": "Device UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Success",
|
200: "Success",
|
||||||
@ -77,12 +79,11 @@ class DynamipsDeviceHandler:
|
|||||||
device = dynamips_manager.get_device(request.match_info["device_id"], project_id=request.match_info["project_id"])
|
device = dynamips_manager.get_device(request.match_info["device_id"], project_id=request.match_info["project_id"])
|
||||||
response.json(device)
|
response.json(device)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}/dynamips/devices/{device_id}",
|
r"/projects/{project_id}/dynamips/devices/{device_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"device_id": "UUID for the instance"
|
"device_id": "Device UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance updated",
|
200: "Instance updated",
|
||||||
@ -107,12 +108,11 @@ class DynamipsDeviceHandler:
|
|||||||
|
|
||||||
response.json(device)
|
response.json(device)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/dynamips/devices/{device_id}",
|
r"/projects/{project_id}/dynamips/devices/{device_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"device_id": "UUID for the instance"
|
"device_id": "Device UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance deleted",
|
204: "Instance deleted",
|
||||||
@ -129,8 +129,8 @@ class DynamipsDeviceHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"device_id": "UUID for the instance",
|
"device_id": "Device UUID",
|
||||||
"port_number": "Port on the device"
|
"port_number": "Port on the device"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
@ -162,12 +162,11 @@ class DynamipsDeviceHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(nio)
|
response.json(nio)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"device_id": "UUID for the instance",
|
"device_id": "Device UUID",
|
||||||
"port_number": "Port on the device"
|
"port_number": "Port on the device"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
@ -188,8 +187,8 @@ class DynamipsDeviceHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/start_capture",
|
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/start_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"device_id": "UUID for the instance",
|
"device_id": "Device UUID",
|
||||||
"port_number": "Port on the device"
|
"port_number": "Port on the device"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
@ -211,8 +210,8 @@ class DynamipsDeviceHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/stop_capture",
|
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/stop_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"device_id": "UUID for the instance",
|
"device_id": "Device UUID",
|
||||||
"port_number": "Port on the device"
|
"port_number": "Port on the device"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
|
@ -19,17 +19,23 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....schemas.nio import NIO_SCHEMA
|
from gns3server.schemas.nio import NIO_SCHEMA
|
||||||
from ....schemas.dynamips_vm import VM_CREATE_SCHEMA
|
from gns3server.compute.dynamips import Dynamips
|
||||||
from ....schemas.dynamips_vm import VM_UPDATE_SCHEMA
|
from gns3server.compute.dynamips.dynamips_error import DynamipsError
|
||||||
from ....schemas.dynamips_vm import VM_OBJECT_SCHEMA
|
from gns3server.compute.project_manager import ProjectManager
|
||||||
from ....schemas.dynamips_vm import VM_CONFIGS_SCHEMA
|
|
||||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
from gns3server.schemas.node import (
|
||||||
from ....schemas.node import NODE_LIST_IMAGES_SCHEMA
|
NODE_CAPTURE_SCHEMA,
|
||||||
from ....compute.dynamips import Dynamips
|
NODE_LIST_IMAGES_SCHEMA,
|
||||||
from ....compute.dynamips.dynamips_error import DynamipsError
|
)
|
||||||
from ....compute.project_manager import ProjectManager
|
|
||||||
|
from gns3server.schemas.dynamips_vm import (
|
||||||
|
VM_CREATE_SCHEMA,
|
||||||
|
VM_UPDATE_SCHEMA,
|
||||||
|
VM_OBJECT_SCHEMA,
|
||||||
|
VM_CONFIGS_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
DEFAULT_CHASSIS = {
|
DEFAULT_CHASSIS = {
|
||||||
"c1700": "1720",
|
"c1700": "1720",
|
||||||
@ -44,11 +50,10 @@ class DynamipsVMHandler:
|
|||||||
API entry points for Dynamips VMs.
|
API entry points for Dynamips VMs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes",
|
r"/projects/{project_id}/dynamips/nodes",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
201: "Instance created",
|
||||||
@ -66,24 +71,23 @@ class DynamipsVMHandler:
|
|||||||
if platform in DEFAULT_CHASSIS:
|
if platform in DEFAULT_CHASSIS:
|
||||||
default_chassis = DEFAULT_CHASSIS[platform]
|
default_chassis = DEFAULT_CHASSIS[platform]
|
||||||
vm = yield from dynamips_manager.create_node(request.json.pop("name"),
|
vm = yield from dynamips_manager.create_node(request.json.pop("name"),
|
||||||
request.match_info["project_id"],
|
request.match_info["project_id"],
|
||||||
request.json.get("node_id"),
|
request.json.get("node_id"),
|
||||||
request.json.get("dynamips_id"),
|
request.json.get("dynamips_id"),
|
||||||
platform,
|
platform,
|
||||||
console=request.json.get("console"),
|
console=request.json.get("console"),
|
||||||
aux=request.json.get("aux"),
|
aux=request.json.get("aux"),
|
||||||
chassis=request.json.pop("chassis", default_chassis))
|
chassis=request.json.pop("chassis", default_chassis))
|
||||||
|
|
||||||
yield from dynamips_manager.update_vm_settings(vm, request.json)
|
yield from dynamips_manager.update_vm_settings(vm, request.json)
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Success",
|
200: "Success",
|
||||||
@ -98,12 +102,11 @@ class DynamipsVMHandler:
|
|||||||
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance updated",
|
200: "Instance updated",
|
||||||
@ -121,12 +124,11 @@ class DynamipsVMHandler:
|
|||||||
yield from dynamips_manager.update_vm_settings(vm, request.json)
|
yield from dynamips_manager.update_vm_settings(vm, request.json)
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance deleted",
|
204: "Instance deleted",
|
||||||
@ -138,16 +140,14 @@ class DynamipsVMHandler:
|
|||||||
|
|
||||||
# check the project_id exists
|
# check the project_id exists
|
||||||
ProjectManager.instance().get_project(request.match_info["project_id"])
|
ProjectManager.instance().get_project(request.match_info["project_id"])
|
||||||
|
|
||||||
yield from Dynamips.instance().delete_node(request.match_info["node_id"])
|
yield from Dynamips.instance().delete_node(request.match_info["node_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/start",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/start",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance started",
|
204: "Instance started",
|
||||||
@ -166,12 +166,11 @@ class DynamipsVMHandler:
|
|||||||
yield from vm.start()
|
yield from vm.start()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/stop",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/stop",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance stopped",
|
204: "Instance stopped",
|
||||||
@ -186,12 +185,11 @@ class DynamipsVMHandler:
|
|||||||
yield from vm.stop()
|
yield from vm.stop()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/suspend",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/suspend",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance suspended",
|
204: "Instance suspended",
|
||||||
@ -206,12 +204,11 @@ class DynamipsVMHandler:
|
|||||||
yield from vm.suspend()
|
yield from vm.suspend()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/resume",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/resume",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance resumed",
|
204: "Instance resumed",
|
||||||
@ -226,12 +223,11 @@ class DynamipsVMHandler:
|
|||||||
yield from vm.resume()
|
yield from vm.resume()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/reload",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/reload",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance reloaded",
|
204: "Instance reloaded",
|
||||||
@ -249,8 +245,8 @@ class DynamipsVMHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter where the nio should be added",
|
"adapter_number": "Adapter where the nio should be added",
|
||||||
"port_number": "Port on the adapter"
|
"port_number": "Port on the adapter"
|
||||||
},
|
},
|
||||||
@ -273,12 +269,11 @@ class DynamipsVMHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(nio)
|
response.json(nio)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter from where the nio should be removed",
|
"adapter_number": "Adapter from where the nio should be removed",
|
||||||
"port_number": "Port on the adapter"
|
"port_number": "Port on the adapter"
|
||||||
},
|
},
|
||||||
@ -301,8 +296,8 @@ class DynamipsVMHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to start a packet capture",
|
"adapter_number": "Adapter to start a packet capture",
|
||||||
"port_number": "Port on the adapter"
|
"port_number": "Port on the adapter"
|
||||||
},
|
},
|
||||||
@ -334,8 +329,8 @@ class DynamipsVMHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to stop a packet capture",
|
"adapter_number": "Adapter to stop a packet capture",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -356,6 +351,10 @@ class DynamipsVMHandler:
|
|||||||
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/configs",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/configs",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Configs retrieved",
|
200: "Configs retrieved",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
@ -375,7 +374,7 @@ class DynamipsVMHandler:
|
|||||||
startup_config_content = base64.b64decode(startup_config_base64).decode("utf-8", errors='replace')
|
startup_config_content = base64.b64decode(startup_config_base64).decode("utf-8", errors='replace')
|
||||||
result["startup_config_content"] = startup_config_content
|
result["startup_config_content"] = startup_config_content
|
||||||
else:
|
else:
|
||||||
# nvram doesn't contain anything if the router has not been started at least once
|
# The NVRAM doesn't contain anything if the router has not been started at least once
|
||||||
# in this case just use the startup-config file
|
# in this case just use the startup-config file
|
||||||
if vm.startup_config:
|
if vm.startup_config:
|
||||||
startup_config_path = os.path.join(module_workdir, vm.startup_config)
|
startup_config_path = os.path.join(module_workdir, vm.startup_config)
|
||||||
@ -392,7 +391,7 @@ class DynamipsVMHandler:
|
|||||||
private_config_content = base64.b64decode(private_config_base64).decode("utf-8", errors='replace')
|
private_config_content = base64.b64decode(private_config_base64).decode("utf-8", errors='replace')
|
||||||
result["private_config_content"] = private_config_content
|
result["private_config_content"] = private_config_content
|
||||||
else:
|
else:
|
||||||
# nvram doesn't contain anything if the router has not been started at least once
|
# The NVRAM doesn't contain anything if the router has not been started at least once
|
||||||
# in this case just use the private-config file
|
# in this case just use the private-config file
|
||||||
if vm.private_config:
|
if vm.private_config:
|
||||||
private_config_path = os.path.join(module_workdir, vm.private_config)
|
private_config_path = os.path.join(module_workdir, vm.private_config)
|
||||||
@ -410,6 +409,10 @@ class DynamipsVMHandler:
|
|||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/configs/save",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/configs/save",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Configs saved",
|
200: "Configs saved",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
@ -425,6 +428,10 @@ class DynamipsVMHandler:
|
|||||||
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/idlepc_proposals",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/idlepc_proposals",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Idle-PCs retrieved",
|
200: "Idle-PCs retrieved",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
@ -442,6 +449,10 @@ class DynamipsVMHandler:
|
|||||||
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/auto_idlepc",
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/auto_idlepc",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Best Idle-pc value found",
|
200: "Best Idle-pc value found",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
@ -457,28 +468,31 @@ class DynamipsVMHandler:
|
|||||||
response.json({"idlepc": idlepc})
|
response.json({"idlepc": idlepc})
|
||||||
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/dynamips/nodes",
|
r"/dynamips/images",
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "List of Dynamips VM retrieved",
|
200: "List of Dynamips IOS images",
|
||||||
},
|
},
|
||||||
description="Retrieve the list of Dynamips VMS",
|
description="Retrieve the list of Dynamips IOS images",
|
||||||
output=NODE_LIST_IMAGES_SCHEMA)
|
output=NODE_LIST_IMAGES_SCHEMA)
|
||||||
def list_vms(request, response):
|
def list_images(request, response):
|
||||||
|
|
||||||
dynamips_manager = Dynamips.instance()
|
dynamips_manager = Dynamips.instance()
|
||||||
vms = yield from dynamips_manager.list_images()
|
images = yield from dynamips_manager.list_images()
|
||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
response.json(vms)
|
response.json(images)
|
||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/dynamips/nodes/{path}",
|
r"/dynamips/images/{filename:.+}",
|
||||||
|
parameters={
|
||||||
|
"filename": "Image filename"
|
||||||
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Image uploaded",
|
204: "Upload a Dynamips IOS image",
|
||||||
},
|
},
|
||||||
raw=True,
|
raw=True,
|
||||||
description="Upload Dynamips image")
|
description="Upload a Dynamips IOS image")
|
||||||
def upload_image(request, response):
|
def upload_image(request, response):
|
||||||
|
|
||||||
dynamips_manager = Dynamips.instance()
|
dynamips_manager = Dynamips.instance()
|
||||||
yield from dynamips_manager.write_image(request.match_info["path"], request.content)
|
yield from dynamips_manager.write_image(request.match_info["filename"], request.content)
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
@ -18,16 +18,22 @@
|
|||||||
import os
|
import os
|
||||||
from aiohttp.web import HTTPConflict
|
from aiohttp.web import HTTPConflict
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....schemas.nio import NIO_SCHEMA
|
from gns3server.schemas.nio import NIO_SCHEMA
|
||||||
from ....schemas.iou import IOU_CREATE_SCHEMA
|
from gns3server.compute.iou import IOU
|
||||||
from ....schemas.iou import IOU_START_SCHEMA
|
|
||||||
from ....schemas.iou import IOU_UPDATE_SCHEMA
|
from gns3server.schemas.node import (
|
||||||
from ....schemas.iou import IOU_OBJECT_SCHEMA
|
NODE_CAPTURE_SCHEMA,
|
||||||
from ....schemas.iou import IOU_CONFIGS_SCHEMA
|
NODE_LIST_IMAGES_SCHEMA,
|
||||||
from ....schemas.node import NODE_LIST_IMAGES_SCHEMA
|
)
|
||||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
|
||||||
from ....compute.iou import IOU
|
from gns3server.schemas.iou import (
|
||||||
|
IOU_CREATE_SCHEMA,
|
||||||
|
IOU_START_SCHEMA,
|
||||||
|
IOU_UPDATE_SCHEMA,
|
||||||
|
IOU_OBJECT_SCHEMA,
|
||||||
|
IOU_CONFIGS_SCHEMA,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class IOUHandler:
|
class IOUHandler:
|
||||||
@ -36,11 +42,10 @@ class IOUHandler:
|
|||||||
API entry points for IOU.
|
API entry points for IOU.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/iou/nodes",
|
r"/projects/{project_id}/iou/nodes",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
201: "Instance created",
|
||||||
@ -72,19 +77,18 @@ class IOUHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}",
|
r"/projects/{project_id}/iou/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Success",
|
200: "Success",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
404: "Instance doesn't exist"
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Get a IOU instance",
|
description="Get an IOU instance",
|
||||||
output=IOU_OBJECT_SCHEMA)
|
output=IOU_OBJECT_SCHEMA)
|
||||||
def show(request, response):
|
def show(request, response):
|
||||||
|
|
||||||
@ -92,12 +96,11 @@ class IOUHandler:
|
|||||||
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}",
|
r"/projects/{project_id}/iou/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance updated",
|
200: "Instance updated",
|
||||||
@ -105,7 +108,7 @@ class IOUHandler:
|
|||||||
404: "Instance doesn't exist",
|
404: "Instance doesn't exist",
|
||||||
409: "Conflict"
|
409: "Conflict"
|
||||||
},
|
},
|
||||||
description="Update a IOU instance",
|
description="Update an IOU instance",
|
||||||
input=IOU_UPDATE_SCHEMA,
|
input=IOU_UPDATE_SCHEMA,
|
||||||
output=IOU_OBJECT_SCHEMA)
|
output=IOU_OBJECT_SCHEMA)
|
||||||
def update(request, response):
|
def update(request, response):
|
||||||
@ -122,30 +125,28 @@ class IOUHandler:
|
|||||||
vm.private_config = request.json.get("private_config_content")
|
vm.private_config = request.json.get("private_config_content")
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}",
|
r"/projects/{project_id}/iou/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance deleted",
|
204: "Instance deleted",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
404: "Instance doesn't exist"
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Delete a IOU instance")
|
description="Delete an IOU instance")
|
||||||
def delete(request, response):
|
def delete(request, response):
|
||||||
|
|
||||||
yield from IOU.instance().delete_node(request.match_info["node_id"])
|
yield from IOU.instance().delete_node(request.match_info["node_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}/start",
|
r"/projects/{project_id}/iou/nodes/{node_id}/start",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance started",
|
200: "Instance started",
|
||||||
@ -154,7 +155,7 @@ class IOUHandler:
|
|||||||
},
|
},
|
||||||
input=IOU_START_SCHEMA,
|
input=IOU_START_SCHEMA,
|
||||||
output=IOU_OBJECT_SCHEMA,
|
output=IOU_OBJECT_SCHEMA,
|
||||||
description="Start a IOU instance")
|
description="Start an IOU instance")
|
||||||
def start(request, response):
|
def start(request, response):
|
||||||
|
|
||||||
iou_manager = IOU.instance()
|
iou_manager = IOU.instance()
|
||||||
@ -167,19 +168,18 @@ class IOUHandler:
|
|||||||
yield from vm.start()
|
yield from vm.start()
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}/stop",
|
r"/projects/{project_id}/iou/nodes/{node_id}/stop",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance stopped",
|
204: "Instance stopped",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
404: "Instance doesn't exist"
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Stop a IOU instance")
|
description="Stop an IOU instance")
|
||||||
def stop(request, response):
|
def stop(request, response):
|
||||||
|
|
||||||
iou_manager = IOU.instance()
|
iou_manager = IOU.instance()
|
||||||
@ -187,19 +187,18 @@ class IOUHandler:
|
|||||||
yield from vm.stop()
|
yield from vm.stop()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}/reload",
|
r"/projects/{project_id}/iou/nodes/{node_id}/reload",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance reloaded",
|
204: "Instance reloaded",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
404: "Instance doesn't exist"
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Reload a IOU instance")
|
description="Reload an IOU instance")
|
||||||
def reload(request, response):
|
def reload(request, response):
|
||||||
|
|
||||||
iou_manager = IOU.instance()
|
iou_manager = IOU.instance()
|
||||||
@ -210,8 +209,8 @@ class IOUHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Network adapter where the nio is located",
|
"adapter_number": "Network adapter where the nio is located",
|
||||||
"port_number": "Port where the nio should be added"
|
"port_number": "Port where the nio should be added"
|
||||||
},
|
},
|
||||||
@ -235,12 +234,11 @@ class IOUHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(nio)
|
response.json(nio)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Network adapter where the nio is located",
|
"adapter_number": "Network adapter where the nio is located",
|
||||||
"port_number": "Port from where the nio should be removed"
|
"port_number": "Port from where the nio should be removed"
|
||||||
},
|
},
|
||||||
@ -260,8 +258,8 @@ class IOUHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to start a packet capture",
|
"adapter_number": "Adapter to start a packet capture",
|
||||||
"port_number": "Port on the adapter"
|
"port_number": "Port on the adapter"
|
||||||
},
|
},
|
||||||
@ -271,7 +269,7 @@ class IOUHandler:
|
|||||||
404: "Instance doesn't exist",
|
404: "Instance doesn't exist",
|
||||||
409: "VM not started"
|
409: "VM not started"
|
||||||
},
|
},
|
||||||
description="Start a packet capture on a IOU VM instance",
|
description="Start a packet capture on an IOU VM instance",
|
||||||
input=NODE_CAPTURE_SCHEMA)
|
input=NODE_CAPTURE_SCHEMA)
|
||||||
def start_capture(request, response):
|
def start_capture(request, response):
|
||||||
|
|
||||||
@ -288,8 +286,8 @@ class IOUHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to stop a packet capture",
|
"adapter_number": "Adapter to stop a packet capture",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -299,7 +297,7 @@ class IOUHandler:
|
|||||||
404: "Instance doesn't exist",
|
404: "Instance doesn't exist",
|
||||||
409: "VM not started"
|
409: "VM not started"
|
||||||
},
|
},
|
||||||
description="Stop a packet capture on a IOU VM instance")
|
description="Stop a packet capture on an IOU VM instance")
|
||||||
def stop_capture(request, response):
|
def stop_capture(request, response):
|
||||||
|
|
||||||
iou_manager = IOU.instance()
|
iou_manager = IOU.instance()
|
||||||
@ -315,6 +313,10 @@ class IOUHandler:
|
|||||||
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}/configs",
|
r"/projects/{project_id}/iou/nodes/{node_id}/configs",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID"
|
||||||
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Configs retrieved",
|
200: "Configs retrieved",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
@ -352,6 +354,10 @@ class IOUHandler:
|
|||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/iou/nodes/{node_id}/configs/save",
|
r"/projects/{project_id}/iou/nodes/{node_id}/configs/save",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID"
|
||||||
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Configs saved",
|
200: "Configs saved",
|
||||||
400: "Invalid request",
|
400: "Invalid request",
|
||||||
@ -366,28 +372,31 @@ class IOUHandler:
|
|||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/iou/nodes",
|
r"/iou/images",
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "List of IOU VM retrieved",
|
200: "List of IOU images",
|
||||||
},
|
},
|
||||||
description="Retrieve the list of IOU VMS",
|
description="Retrieve the list of IOU images",
|
||||||
output=NODE_LIST_IMAGES_SCHEMA)
|
output=NODE_LIST_IMAGES_SCHEMA)
|
||||||
def list_iou_nodes(request, response):
|
def list_iou_images(request, response):
|
||||||
|
|
||||||
iou_manager = IOU.instance()
|
iou_manager = IOU.instance()
|
||||||
iou_nodes = yield from iou_manager.list_images()
|
images = yield from iou_manager.list_images()
|
||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
response.json(iou_nodes)
|
response.json(images)
|
||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/iou/nodes/{path}",
|
r"/iou/images/{filename:.+}",
|
||||||
|
parameters={
|
||||||
|
"filename": "Image filename"
|
||||||
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Image uploaded",
|
204: "Image uploaded",
|
||||||
},
|
},
|
||||||
raw=True,
|
raw=True,
|
||||||
description="Upload IOU image.")
|
description="Upload an IOU image")
|
||||||
def upload_image(request, response):
|
def upload_image(request, response):
|
||||||
|
|
||||||
iou_manager = IOU.instance()
|
iou_manager = IOU.instance()
|
||||||
yield from iou_manager.write_image(request.match_info["path"], request.content)
|
yield from iou_manager.write_image(request.match_info["filename"], request.content)
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
@ -15,19 +15,18 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....compute.port_manager import PortManager
|
from gns3server.compute.port_manager import PortManager
|
||||||
from ....compute.project_manager import ProjectManager
|
from gns3server.compute.project_manager import ProjectManager
|
||||||
from ....utils.interfaces import interfaces
|
from gns3server.utils.interfaces import interfaces
|
||||||
|
|
||||||
|
|
||||||
class NetworkHandler:
|
class NetworkHandler:
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/ports/udp",
|
r"/projects/{project_id}/ports/udp",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "UDP port allocated",
|
201: "UDP port allocated",
|
||||||
@ -43,7 +42,6 @@ class NetworkHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json({"udp_port": udp_port})
|
response.json({"udp_port": udp_port})
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/interfaces",
|
r"/interfaces",
|
||||||
description="List all the network interfaces available on the server")
|
description="List all the network interfaces available on the server")
|
||||||
|
@ -17,17 +17,16 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from ....web.route import Route
|
|
||||||
from ....compute.notification_manager import NotificationManager
|
|
||||||
from aiohttp.web import WebSocketResponse
|
from aiohttp.web import WebSocketResponse
|
||||||
|
from gns3server.web.route import Route
|
||||||
|
from gns3server.compute.notification_manager import NotificationManager
|
||||||
|
|
||||||
|
|
||||||
class NotificationHandler:
|
class NotificationHandler:
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/notifications/ws",
|
r"/notifications/ws",
|
||||||
description="Send notifications about what happend using websockets")
|
description="Send notifications using Websockets")
|
||||||
def notifications(request, response):
|
def notifications(request, response):
|
||||||
notifications = NotificationManager.instance()
|
notifications = NotificationManager.instance()
|
||||||
ws = WebSocketResponse()
|
ws = WebSocketResponse()
|
||||||
@ -36,8 +35,8 @@ class NotificationHandler:
|
|||||||
with notifications.queue() as queue:
|
with notifications.queue() as queue:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
notif = yield from queue.get_json(5)
|
notification = yield from queue.get_json(5)
|
||||||
except asyncio.futures.CancelledError as e:
|
except asyncio.futures.CancelledError:
|
||||||
break
|
break
|
||||||
ws.send_str(notif)
|
ws.send_str(notification)
|
||||||
return ws
|
return ws
|
||||||
|
@ -22,10 +22,17 @@ import os
|
|||||||
import psutil
|
import psutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....schemas.project import PROJECT_OBJECT_SCHEMA, PROJECT_CREATE_SCHEMA, PROJECT_UPDATE_SCHEMA, PROJECT_FILE_LIST_SCHEMA, PROJECT_LIST_SCHEMA
|
from gns3server.compute.project_manager import ProjectManager
|
||||||
from ....compute.project_manager import ProjectManager
|
from gns3server.compute import MODULES
|
||||||
from ....compute import MODULES
|
|
||||||
|
from gns3server.schemas.project import (
|
||||||
|
PROJECT_OBJECT_SCHEMA,
|
||||||
|
PROJECT_CREATE_SCHEMA,
|
||||||
|
PROJECT_UPDATE_SCHEMA,
|
||||||
|
PROJECT_FILE_LIST_SCHEMA,
|
||||||
|
PROJECT_LIST_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
@ -33,13 +40,12 @@ log = logging.getLogger()
|
|||||||
|
|
||||||
class ProjectHandler:
|
class ProjectHandler:
|
||||||
|
|
||||||
# How many clients has subcribe to notifications
|
# How many clients have subscribed to notifications
|
||||||
_notifications_listening = {}
|
_notifications_listening = {}
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects",
|
r"/projects",
|
||||||
description="List projects opened on the server",
|
description="List all projects opened on the server",
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Project list",
|
200: "Project list",
|
||||||
},
|
},
|
||||||
@ -51,13 +57,12 @@ class ProjectHandler:
|
|||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
response.json(list(pm.projects))
|
response.json(list(pm.projects))
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects",
|
r"/projects",
|
||||||
description="Create a new project on the server",
|
description="Create a new project on the server",
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Project created",
|
201: "Project created",
|
||||||
403: "You are not allowed to modify this property",
|
403: "Forbidden to create a project",
|
||||||
409: "Project already created"
|
409: "Project already created"
|
||||||
},
|
},
|
||||||
output=PROJECT_OBJECT_SCHEMA,
|
output=PROJECT_OBJECT_SCHEMA,
|
||||||
@ -74,12 +79,11 @@ class ProjectHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(p)
|
response.json(p)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}",
|
r"/projects/{project_id}",
|
||||||
description="Get project information",
|
description="Get project information",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Success",
|
200: "Success",
|
||||||
@ -92,16 +96,15 @@ class ProjectHandler:
|
|||||||
project = pm.get_project(request.match_info["project_id"])
|
project = pm.get_project(request.match_info["project_id"])
|
||||||
response.json(project)
|
response.json(project)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}",
|
r"/projects/{project_id}",
|
||||||
description="Update a project",
|
description="Update a project",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "The project has been updated",
|
200: "Project updated",
|
||||||
403: "You are not allowed to modify this property",
|
403: "Forbidden to update this project",
|
||||||
404: "The project doesn't exist"
|
404: "The project doesn't exist"
|
||||||
},
|
},
|
||||||
output=PROJECT_OBJECT_SCHEMA,
|
output=PROJECT_OBJECT_SCHEMA,
|
||||||
@ -118,16 +121,15 @@ class ProjectHandler:
|
|||||||
for module in MODULES:
|
for module in MODULES:
|
||||||
yield from module.instance().project_moved(project)
|
yield from module.instance().project_moved(project)
|
||||||
yield from project.clean_old_path(old_path)
|
yield from project.clean_old_path(old_path)
|
||||||
# Very important we need to remove temporary flag after moving the project
|
# Very important: we need to remove temporary flag after moving the project
|
||||||
project.temporary = request.json.get("temporary", project.temporary)
|
project.temporary = request.json.get("temporary", project.temporary)
|
||||||
response.json(project)
|
response.json(project)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/commit",
|
r"/projects/{project_id}/commit",
|
||||||
description="Write changes on disk",
|
description="Write changes on disk",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Changes have been written on disk",
|
204: "Changes have been written on disk",
|
||||||
@ -140,15 +142,14 @@ class ProjectHandler:
|
|||||||
yield from project.commit()
|
yield from project.commit()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/close",
|
r"/projects/{project_id}/close",
|
||||||
description="Close a project",
|
description="Close a project",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "The project has been closed",
|
204: "Project closed",
|
||||||
404: "The project doesn't exist"
|
404: "The project doesn't exist"
|
||||||
})
|
})
|
||||||
def close(request, response):
|
def close(request, response):
|
||||||
@ -160,15 +161,14 @@ class ProjectHandler:
|
|||||||
pm.remove_project(project.id)
|
pm.remove_project(project.id)
|
||||||
del ProjectHandler._notifications_listening[project.id]
|
del ProjectHandler._notifications_listening[project.id]
|
||||||
else:
|
else:
|
||||||
log.warning("Skip project closing, another client is listening for project informations")
|
log.warning("Skip project closing, another client is listening for project notifications")
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}",
|
r"/projects/{project_id}",
|
||||||
description="Delete a project from disk",
|
description="Delete a project from disk",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Changes have been written on disk",
|
204: "Changes have been written on disk",
|
||||||
@ -182,12 +182,11 @@ class ProjectHandler:
|
|||||||
pm.remove_project(project.id)
|
pm.remove_project(project.id)
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/notifications",
|
r"/projects/{project_id}/notifications",
|
||||||
description="Receive notifications about the projects",
|
description="Receive notifications about the project",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "End of stream",
|
200: "End of stream",
|
||||||
@ -201,7 +200,7 @@ class ProjectHandler:
|
|||||||
response.content_type = "application/json"
|
response.content_type = "application/json"
|
||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
response.enable_chunked_encoding()
|
response.enable_chunked_encoding()
|
||||||
# Very important: do not send a content lenght otherwise QT close the connection but curl can consume the Feed
|
# Very important: do not send a content length otherwise QT closes the connection (curl can consume the feed)
|
||||||
response.content_length = None
|
response.content_length = None
|
||||||
|
|
||||||
response.start(request)
|
response.start(request)
|
||||||
@ -226,30 +225,27 @@ class ProjectHandler:
|
|||||||
if project.id in ProjectHandler._notifications_listening:
|
if project.id in ProjectHandler._notifications_listening:
|
||||||
ProjectHandler._notifications_listening[project.id] -= 1
|
ProjectHandler._notifications_listening[project.id] -= 1
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _getPingMessage(cls):
|
def _getPingMessage(cls):
|
||||||
"""
|
"""
|
||||||
The ping message is regulary send to the client to
|
Ping messages are regularly sent to the client to
|
||||||
keep the connection open. We send with it some informations
|
keep the connection open. We send with it some information about server load.
|
||||||
about server load.
|
|
||||||
|
|
||||||
:returns: hash
|
:returns: hash
|
||||||
"""
|
"""
|
||||||
stats = {}
|
stats = {}
|
||||||
# Non blocking call in order to get cpu usage. First call will return 0
|
# Non blocking call in order to get cpu usage. First call will return 0.
|
||||||
stats["cpu_usage_percent"] = psutil.cpu_percent(interval=None)
|
stats["cpu_usage_percent"] = psutil.cpu_percent(interval=None)
|
||||||
stats["memory_usage_percent"] = psutil.virtual_memory().percent
|
stats["memory_usage_percent"] = psutil.virtual_memory().percent
|
||||||
return {"action": "ping", "event": stats}
|
return {"action": "ping", "event": stats}
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/files",
|
r"/projects/{project_id}/files",
|
||||||
description="List files of a project",
|
description="List files of a project",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Return list of files",
|
200: "Return a list of files",
|
||||||
404: "The project doesn't exist"
|
404: "The project doesn't exist"
|
||||||
},
|
},
|
||||||
output=PROJECT_FILE_LIST_SCHEMA)
|
output=PROJECT_FILE_LIST_SCHEMA)
|
||||||
@ -261,15 +257,14 @@ class ProjectHandler:
|
|||||||
response.json(files)
|
response.json(files)
|
||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/files/{path:.+}",
|
r"/projects/{project_id}/files/{path:.+}",
|
||||||
description="Get a file of a project",
|
description="Get a file from a project",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Return the file",
|
200: "File returned",
|
||||||
403: "Permission denied",
|
403: "Permission denied",
|
||||||
404: "The file doesn't exist"
|
404: "The file doesn't exist"
|
||||||
})
|
})
|
||||||
@ -280,7 +275,7 @@ class ProjectHandler:
|
|||||||
path = request.match_info["path"]
|
path = request.match_info["path"]
|
||||||
path = os.path.normpath(path)
|
path = os.path.normpath(path)
|
||||||
|
|
||||||
# Raise error if user try to escape
|
# Raise an error if user try to escape
|
||||||
if path[0] == ".":
|
if path[0] == ".":
|
||||||
raise aiohttp.web.HTTPForbidden
|
raise aiohttp.web.HTTPForbidden
|
||||||
path = os.path.join(project.path, path)
|
path = os.path.join(project.path, path)
|
||||||
@ -288,7 +283,7 @@ class ProjectHandler:
|
|||||||
response.content_type = "application/octet-stream"
|
response.content_type = "application/octet-stream"
|
||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
response.enable_chunked_encoding()
|
response.enable_chunked_encoding()
|
||||||
# Very important: do not send a content length otherwise QT close the connection but curl can consume the Feed
|
# Very important: do not send a content length otherwise QT closes the connection (curl can consume the feed)
|
||||||
response.content_length = None
|
response.content_length = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -305,15 +300,14 @@ class ProjectHandler:
|
|||||||
except PermissionError:
|
except PermissionError:
|
||||||
raise aiohttp.web.HTTPForbidden()
|
raise aiohttp.web.HTTPForbidden()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/stream/{path:.+}",
|
r"/projects/{project_id}/stream/{path:.+}",
|
||||||
description="Stream a file from a project",
|
description="Stream a file from a project",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Return the file",
|
200: "File returned",
|
||||||
403: "Permission denied",
|
403: "Permission denied",
|
||||||
404: "The file doesn't exist"
|
404: "The file doesn't exist"
|
||||||
})
|
})
|
||||||
@ -324,7 +318,7 @@ class ProjectHandler:
|
|||||||
path = request.match_info["path"]
|
path = request.match_info["path"]
|
||||||
path = os.path.normpath(path)
|
path = os.path.normpath(path)
|
||||||
|
|
||||||
# Raise error if user try to escape
|
# Raise an error if user try to escape
|
||||||
if path[0] == ".":
|
if path[0] == ".":
|
||||||
raise aiohttp.web.HTTPForbidden
|
raise aiohttp.web.HTTPForbidden
|
||||||
path = os.path.join(project.path, path)
|
path = os.path.join(project.path, path)
|
||||||
@ -332,7 +326,7 @@ class ProjectHandler:
|
|||||||
response.content_type = "application/octet-stream"
|
response.content_type = "application/octet-stream"
|
||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
response.enable_chunked_encoding()
|
response.enable_chunked_encoding()
|
||||||
# Very important: do not send a content length otherwise QT close the connection but curl can consume the Feed
|
# Very important: do not send a content length otherwise QT closes the connection (curl can consume the feed)
|
||||||
response.content_length = None
|
response.content_length = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -349,16 +343,15 @@ class ProjectHandler:
|
|||||||
except PermissionError:
|
except PermissionError:
|
||||||
raise aiohttp.web.HTTPForbidden()
|
raise aiohttp.web.HTTPForbidden()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/files/{path:.+}",
|
r"/projects/{project_id}/files/{path:.+}",
|
||||||
description="Get a file of a project",
|
description="Write a file to a project",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
raw=True,
|
raw=True,
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Return the file",
|
200: "File returned",
|
||||||
403: "Permission denied",
|
403: "Permission denied",
|
||||||
404: "The path doesn't exist"
|
404: "The path doesn't exist"
|
||||||
})
|
})
|
||||||
@ -389,16 +382,15 @@ class ProjectHandler:
|
|||||||
except PermissionError:
|
except PermissionError:
|
||||||
raise aiohttp.web.HTTPForbidden()
|
raise aiohttp.web.HTTPForbidden()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/export",
|
r"/projects/{project_id}/export",
|
||||||
description="Export a project as a portable archive",
|
description="Export a project as a portable archive",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
raw=True,
|
raw=True,
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Return the file",
|
200: "File returned",
|
||||||
404: "The project doesn't exist"
|
404: "The project doesn't exist"
|
||||||
})
|
})
|
||||||
def export_project(request, response):
|
def export_project(request, response):
|
||||||
@ -408,7 +400,7 @@ class ProjectHandler:
|
|||||||
response.content_type = 'application/gns3project'
|
response.content_type = 'application/gns3project'
|
||||||
response.headers['CONTENT-DISPOSITION'] = 'attachment; filename="{}.gns3project"'.format(project.name)
|
response.headers['CONTENT-DISPOSITION'] = 'attachment; filename="{}.gns3project"'.format(project.name)
|
||||||
response.enable_chunked_encoding()
|
response.enable_chunked_encoding()
|
||||||
# Very important: do not send a content length otherwise QT close the connection but curl can consume the Feed
|
# Very important: do not send a content length otherwise QT closes the connection (curl can consume the feed)
|
||||||
response.content_length = None
|
response.content_length = None
|
||||||
response.start(request)
|
response.start(request)
|
||||||
|
|
||||||
@ -418,18 +410,17 @@ class ProjectHandler:
|
|||||||
|
|
||||||
yield from response.write_eof()
|
yield from response.write_eof()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/import",
|
r"/projects/{project_id}/import",
|
||||||
description="Import a project from a portable archive",
|
description="Import a project from a portable archive",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
raw=True,
|
raw=True,
|
||||||
output=PROJECT_OBJECT_SCHEMA,
|
output=PROJECT_OBJECT_SCHEMA,
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Project imported",
|
200: "Project imported",
|
||||||
403: "You are not allowed to modify this property"
|
403: "Forbidden to import project"
|
||||||
})
|
})
|
||||||
def import_project(request, response):
|
def import_project(request, response):
|
||||||
|
|
||||||
@ -437,11 +428,9 @@ class ProjectHandler:
|
|||||||
project_id = request.match_info["project_id"]
|
project_id = request.match_info["project_id"]
|
||||||
project = pm.create_project(project_id=project_id)
|
project = pm.create_project(project_id=project_id)
|
||||||
|
|
||||||
# We write the content to a temporary location
|
# We write the content to a temporary location and after we extract it all.
|
||||||
# and after extract all. It could be more optimal to stream
|
# It could be more optimal to stream this but it is not implemented in Python.
|
||||||
# this but it's not implemented in Python.
|
# Spooled means the file is temporary kept in memory until max_size is reached
|
||||||
#
|
|
||||||
# Spooled mean the file is temporary keep in ram until max_size
|
|
||||||
try:
|
try:
|
||||||
with tempfile.SpooledTemporaryFile(max_size=10000) as temp:
|
with tempfile.SpooledTemporaryFile(max_size=10000) as temp:
|
||||||
while True:
|
while True:
|
||||||
|
@ -19,19 +19,23 @@ import sys
|
|||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from aiohttp.web import HTTPConflict
|
from aiohttp.web import HTTPConflict
|
||||||
from ....web.route import Route
|
|
||||||
from ....compute.project_manager import ProjectManager
|
from gns3server.web.route import Route
|
||||||
from ....schemas.nio import NIO_SCHEMA
|
from gns3server.compute.project_manager import ProjectManager
|
||||||
from ....schemas.qemu import QEMU_CREATE_SCHEMA
|
from gns3server.schemas.nio import NIO_SCHEMA
|
||||||
from ....schemas.qemu import QEMU_UPDATE_SCHEMA
|
from gns3server.schemas.node import NODE_LIST_IMAGES_SCHEMA
|
||||||
from ....schemas.qemu import QEMU_OBJECT_SCHEMA
|
from gns3server.compute.qemu import Qemu
|
||||||
from ....schemas.qemu import QEMU_BINARY_FILTER_SCHEMA
|
from gns3server.config import Config
|
||||||
from ....schemas.qemu import QEMU_BINARY_LIST_SCHEMA
|
|
||||||
from ....schemas.qemu import QEMU_CAPABILITY_LIST_SCHEMA
|
from gns3server.schemas.qemu import (
|
||||||
from ....schemas.qemu import QEMU_IMAGE_CREATE_SCHEMA
|
QEMU_CREATE_SCHEMA,
|
||||||
from ....schemas.node import NODE_LIST_IMAGES_SCHEMA
|
QEMU_UPDATE_SCHEMA,
|
||||||
from ....compute.qemu import Qemu
|
QEMU_OBJECT_SCHEMA,
|
||||||
from ....config import Config
|
QEMU_BINARY_LIST_SCHEMA,
|
||||||
|
QEMU_BINARY_FILTER_SCHEMA,
|
||||||
|
QEMU_CAPABILITY_LIST_SCHEMA,
|
||||||
|
QEMU_IMAGE_CREATE_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class QEMUHandler:
|
class QEMUHandler:
|
||||||
@ -40,11 +44,10 @@ class QEMUHandler:
|
|||||||
API entry points for QEMU.
|
API entry points for QEMU.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/qemu/nodes",
|
r"/projects/{project_id}/qemu/nodes",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
201: "Instance created",
|
||||||
@ -73,12 +76,11 @@ class QEMUHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}",
|
r"/projects/{project_id}/qemu/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Success",
|
200: "Success",
|
||||||
@ -93,12 +95,11 @@ class QEMUHandler:
|
|||||||
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}",
|
r"/projects/{project_id}/qemu/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance updated",
|
200: "Instance updated",
|
||||||
@ -120,12 +121,11 @@ class QEMUHandler:
|
|||||||
|
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}",
|
r"/projects/{project_id}/qemu/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance deleted",
|
204: "Instance deleted",
|
||||||
@ -138,12 +138,11 @@ class QEMUHandler:
|
|||||||
yield from Qemu.instance().delete_node(request.match_info["node_id"])
|
yield from Qemu.instance().delete_node(request.match_info["node_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}/start",
|
r"/projects/{project_id}/qemu/nodes/{node_id}/start",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance started",
|
200: "Instance started",
|
||||||
@ -156,20 +155,18 @@ class QEMUHandler:
|
|||||||
|
|
||||||
qemu_manager = Qemu.instance()
|
qemu_manager = Qemu.instance()
|
||||||
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
if sys.platform.startswith("linux") and qemu_manager.config.get_section_config("Qemu").getboolean("enable_kvm", True) \
|
if sys.platform.startswith("linux") and qemu_manager.config.get_section_config("Qemu").getboolean("enable_kvm", True) and "-no-kvm" not in vm.options:
|
||||||
and "-no-kvm" not in vm.options:
|
|
||||||
pm = ProjectManager.instance()
|
pm = ProjectManager.instance()
|
||||||
if pm.check_hardware_virtualization(vm) is False:
|
if pm.check_hardware_virtualization(vm) is False:
|
||||||
raise HTTPConflict(text="Cannot start VM with KVM enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
|
raise HTTPConflict(text="Cannot start VM with KVM enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
|
||||||
yield from vm.start()
|
yield from vm.start()
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}/stop",
|
r"/projects/{project_id}/qemu/nodes/{node_id}/stop",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"vm_node": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance stopped",
|
204: "Instance stopped",
|
||||||
@ -184,12 +181,11 @@ class QEMUHandler:
|
|||||||
yield from vm.stop()
|
yield from vm.stop()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}/reload",
|
r"/projects/{project_id}/qemu/nodes/{node_id}/reload",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance reloaded",
|
204: "Instance reloaded",
|
||||||
@ -204,12 +200,11 @@ class QEMUHandler:
|
|||||||
yield from vm.reload()
|
yield from vm.reload()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}/suspend",
|
r"/projects/{project_id}/qemu/nodes/{node_id}/suspend",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance suspended",
|
204: "Instance suspended",
|
||||||
@ -224,12 +219,11 @@ class QEMUHandler:
|
|||||||
yield from vm.suspend()
|
yield from vm.suspend()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}/resume",
|
r"/projects/{project_id}/qemu/nodes/{node_id}/resume",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance resumed",
|
204: "Instance resumed",
|
||||||
@ -247,8 +241,8 @@ class QEMUHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Network adapter where the nio is located",
|
"adapter_number": "Network adapter where the nio is located",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -272,12 +266,11 @@ class QEMUHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(nio)
|
response.json(nio)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Network adapter where the nio is located",
|
"adapter_number": "Network adapter where the nio is located",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -294,7 +287,6 @@ class QEMUHandler:
|
|||||||
yield from vm.adapter_remove_nio_binding(int(request.match_info["adapter_number"]))
|
yield from vm.adapter_remove_nio_binding(int(request.match_info["adapter_number"]))
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/qemu/binaries",
|
r"/qemu/binaries",
|
||||||
status_codes={
|
status_codes={
|
||||||
@ -310,7 +302,6 @@ class QEMUHandler:
|
|||||||
binaries = yield from Qemu.binary_list(request.json.get("archs", None))
|
binaries = yield from Qemu.binary_list(request.json.get("archs", None))
|
||||||
response.json(binaries)
|
response.json(binaries)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/qemu/img-binaries",
|
r"/qemu/img-binaries",
|
||||||
status_codes={
|
status_codes={
|
||||||
@ -340,7 +331,6 @@ class QEMUHandler:
|
|||||||
capabilities["kvm"] = kvms
|
capabilities["kvm"] = kvms
|
||||||
response.json(capabilities)
|
response.json(capabilities)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/qemu/img",
|
r"/qemu/img",
|
||||||
status_codes={
|
status_codes={
|
||||||
@ -363,28 +353,31 @@ class QEMUHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/qemu/nodes",
|
r"/qemu/images",
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "List of Qemu images retrieved",
|
200: "List of Qemu images",
|
||||||
},
|
},
|
||||||
description="Retrieve the list of Qemu images",
|
description="Retrieve the list of Qemu images",
|
||||||
output=NODE_LIST_IMAGES_SCHEMA)
|
output=NODE_LIST_IMAGES_SCHEMA)
|
||||||
def list_vm_nodes(request, response):
|
def list_qemu_images(request, response):
|
||||||
|
|
||||||
qemu_manager = Qemu.instance()
|
qemu_manager = Qemu.instance()
|
||||||
vm_nodes = yield from qemu_manager.list_images()
|
images = yield from qemu_manager.list_images()
|
||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
response.json(vm_nodes)
|
response.json(images)
|
||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/qemu/nodes/{path:.+}",
|
r"/qemu/images/{filename:.+}",
|
||||||
|
parameters={
|
||||||
|
"filename": "Image filename"
|
||||||
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Image uploaded",
|
204: "Image uploaded",
|
||||||
},
|
},
|
||||||
raw=True,
|
raw=True,
|
||||||
description="Upload Qemu image.")
|
description="Upload Qemu image")
|
||||||
def upload_image(request, response):
|
def upload_image(request, response):
|
||||||
|
|
||||||
qemu_manager = Qemu.instance()
|
qemu_manager = Qemu.instance()
|
||||||
yield from qemu_manager.write_image(request.match_info["path"], request.content)
|
yield from qemu_manager.write_image(request.match_info["filename"], request.content)
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
@ -15,16 +15,15 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....config import Config
|
from gns3server.config import Config
|
||||||
from ....schemas.version import VERSION_SCHEMA
|
from gns3server.schemas.version import VERSION_SCHEMA
|
||||||
from ....version import __version__
|
from gns3server.version import __version__
|
||||||
from aiohttp.web import HTTPConflict
|
from aiohttp.web import HTTPConflict
|
||||||
|
|
||||||
|
|
||||||
class VersionHandler:
|
class VersionHandler:
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/version",
|
r"/version",
|
||||||
description="Retrieve the server version number",
|
description="Retrieve the server version number",
|
||||||
@ -35,7 +34,6 @@ class VersionHandler:
|
|||||||
local_server = config.get_section_config("Server").getboolean("local", False)
|
local_server = config.get_section_config("Server").getboolean("local", False)
|
||||||
response.json({"version": __version__, "local": local_server})
|
response.json({"version": __version__, "local": local_server})
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/version",
|
r"/version",
|
||||||
description="Check if version is the same as the server",
|
description="Check if version is the same as the server",
|
||||||
|
@ -18,15 +18,17 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from aiohttp.web import HTTPConflict
|
from aiohttp.web import HTTPConflict
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....schemas.nio import NIO_SCHEMA
|
from gns3server.schemas.nio import NIO_SCHEMA
|
||||||
from ....schemas.virtualbox import VBOX_CREATE_SCHEMA
|
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
|
||||||
from ....schemas.virtualbox import VBOX_UPDATE_SCHEMA
|
from gns3server.compute.virtualbox import VirtualBox
|
||||||
from ....schemas.virtualbox import VBOX_OBJECT_SCHEMA
|
from gns3server.compute.project_manager import ProjectManager
|
||||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
|
||||||
from ....compute.virtualbox import VirtualBox
|
|
||||||
from ....compute.project_manager import ProjectManager
|
|
||||||
|
|
||||||
|
from gns3server.schemas.virtualbox import (
|
||||||
|
VBOX_CREATE_SCHEMA,
|
||||||
|
VBOX_UPDATE_SCHEMA,
|
||||||
|
VBOX_OBJECT_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
class VirtualBoxHandler:
|
class VirtualBoxHandler:
|
||||||
|
|
||||||
@ -34,24 +36,10 @@ class VirtualBoxHandler:
|
|||||||
API entry points for VirtualBox.
|
API entry points for VirtualBox.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
|
||||||
r"/virtualbox/vms",
|
|
||||||
status_codes={
|
|
||||||
200: "Success",
|
|
||||||
},
|
|
||||||
description="Get all available VirtualBox VMs")
|
|
||||||
def index(request, response):
|
|
||||||
|
|
||||||
vbox_manager = VirtualBox.instance()
|
|
||||||
vms = yield from vbox_manager.list_images()
|
|
||||||
response.json(vms)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/virtualbox/nodes",
|
r"/projects/{project_id}/virtualbox/nodes",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
201: "Instance created",
|
||||||
@ -88,12 +76,11 @@ class VirtualBoxHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Success",
|
200: "Success",
|
||||||
@ -108,12 +95,11 @@ class VirtualBoxHandler:
|
|||||||
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance updated",
|
200: "Instance updated",
|
||||||
@ -153,12 +139,11 @@ class VirtualBoxHandler:
|
|||||||
|
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance deleted",
|
204: "Instance deleted",
|
||||||
@ -170,16 +155,14 @@ class VirtualBoxHandler:
|
|||||||
|
|
||||||
# check the project_id exists
|
# check the project_id exists
|
||||||
ProjectManager.instance().get_project(request.match_info["project_id"])
|
ProjectManager.instance().get_project(request.match_info["project_id"])
|
||||||
|
|
||||||
yield from VirtualBox.instance().delete_node(request.match_info["node_id"])
|
yield from VirtualBox.instance().delete_node(request.match_info["node_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/start",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/start",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance started",
|
204: "Instance started",
|
||||||
@ -198,12 +181,11 @@ class VirtualBoxHandler:
|
|||||||
yield from vm.start()
|
yield from vm.start()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/stop",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/stop",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance stopped",
|
204: "Instance stopped",
|
||||||
@ -218,12 +200,11 @@ class VirtualBoxHandler:
|
|||||||
yield from vm.stop()
|
yield from vm.stop()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/suspend",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/suspend",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance suspended",
|
204: "Instance suspended",
|
||||||
@ -238,12 +219,11 @@ class VirtualBoxHandler:
|
|||||||
yield from vm.suspend()
|
yield from vm.suspend()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/resume",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/resume",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance resumed",
|
204: "Instance resumed",
|
||||||
@ -258,12 +238,11 @@ class VirtualBoxHandler:
|
|||||||
yield from vm.resume()
|
yield from vm.resume()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/reload",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/reload",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance reloaded",
|
204: "Instance reloaded",
|
||||||
@ -281,8 +260,8 @@ class VirtualBoxHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter where the nio should be added",
|
"adapter_number": "Adapter where the nio should be added",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -306,12 +285,11 @@ class VirtualBoxHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(nio)
|
response.json(nio)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter from where the nio should be removed",
|
"adapter_number": "Adapter from where the nio should be removed",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -331,8 +309,8 @@ class VirtualBoxHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to start a packet capture",
|
"adapter_number": "Adapter to start a packet capture",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -355,8 +333,8 @@ class VirtualBoxHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to stop a packet capture",
|
"adapter_number": "Adapter to stop a packet capture",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -372,3 +350,14 @@ class VirtualBoxHandler:
|
|||||||
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
vm.stop_capture(int(request.match_info["adapter_number"]))
|
vm.stop_capture(int(request.match_info["adapter_number"]))
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
|
@Route.get(
|
||||||
|
r"/virtualbox/vms",
|
||||||
|
status_codes={
|
||||||
|
200: "Success",
|
||||||
|
},
|
||||||
|
description="Get all available VirtualBox VMs")
|
||||||
|
def get_vms(request, response):
|
||||||
|
vbox_manager = VirtualBox.instance()
|
||||||
|
vms = yield from vbox_manager.list_vms()
|
||||||
|
response.json(vms)
|
||||||
|
@ -18,14 +18,17 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from aiohttp.web import HTTPConflict
|
from aiohttp.web import HTTPConflict
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....schemas.vmware import VMWARE_CREATE_SCHEMA
|
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
|
||||||
from ....schemas.vmware import VMWARE_UPDATE_SCHEMA
|
from gns3server.schemas.nio import NIO_SCHEMA
|
||||||
from ....schemas.vmware import VMWARE_OBJECT_SCHEMA
|
from gns3server.compute.vmware import VMware
|
||||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
from gns3server.compute.project_manager import ProjectManager
|
||||||
from ....schemas.nio import NIO_SCHEMA
|
|
||||||
from ....compute.vmware import VMware
|
from gns3server.schemas.vmware import (
|
||||||
from ....compute.project_manager import ProjectManager
|
VMWARE_CREATE_SCHEMA,
|
||||||
|
VMWARE_UPDATE_SCHEMA,
|
||||||
|
VMWARE_OBJECT_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class VMwareHandler:
|
class VMwareHandler:
|
||||||
@ -34,24 +37,10 @@ class VMwareHandler:
|
|||||||
API entry points for VMware.
|
API entry points for VMware.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
|
||||||
r"/vmware/vms",
|
|
||||||
status_codes={
|
|
||||||
200: "Success",
|
|
||||||
},
|
|
||||||
description="Get all VMware VMs available")
|
|
||||||
def index(request, response):
|
|
||||||
|
|
||||||
vmware_manager = VMware.instance()
|
|
||||||
vms = yield from vmware_manager.list_vms()
|
|
||||||
response.json(vms)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes",
|
r"/projects/{project_id}/vmware/nodes",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
201: "Instance created",
|
||||||
@ -79,12 +68,11 @@ class VMwareHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}",
|
r"/projects/{project_id}/vmware/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Success",
|
200: "Success",
|
||||||
@ -99,12 +87,11 @@ class VMwareHandler:
|
|||||||
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}",
|
r"/projects/{project_id}/vmware/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance updated",
|
200: "Instance updated",
|
||||||
@ -126,12 +113,11 @@ class VMwareHandler:
|
|||||||
|
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}",
|
r"/projects/{project_id}/vmware/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance deleted",
|
204: "Instance deleted",
|
||||||
@ -146,12 +132,11 @@ class VMwareHandler:
|
|||||||
yield from VMware.instance().delete_node(request.match_info["node_id"])
|
yield from VMware.instance().delete_node(request.match_info["node_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/start",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/start",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance started",
|
204: "Instance started",
|
||||||
@ -170,12 +155,11 @@ class VMwareHandler:
|
|||||||
yield from vm.start()
|
yield from vm.start()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/stop",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/stop",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance stopped",
|
204: "Instance stopped",
|
||||||
@ -190,12 +174,11 @@ class VMwareHandler:
|
|||||||
yield from vm.stop()
|
yield from vm.stop()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/suspend",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/suspend",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance suspended",
|
204: "Instance suspended",
|
||||||
@ -210,12 +193,11 @@ class VMwareHandler:
|
|||||||
yield from vm.suspend()
|
yield from vm.suspend()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/resume",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/resume",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance resumed",
|
204: "Instance resumed",
|
||||||
@ -230,12 +212,11 @@ class VMwareHandler:
|
|||||||
yield from vm.resume()
|
yield from vm.resume()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/reload",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/reload",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance reloaded",
|
204: "Instance reloaded",
|
||||||
@ -253,8 +234,8 @@ class VMwareHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter where the nio should be added",
|
"adapter_number": "Adapter where the nio should be added",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -278,12 +259,11 @@ class VMwareHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(nio)
|
response.json(nio)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter from where the nio should be removed",
|
"adapter_number": "Adapter from where the nio should be removed",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -303,8 +283,8 @@ class VMwareHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to start a packet capture",
|
"adapter_number": "Adapter to start a packet capture",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -327,8 +307,8 @@ class VMwareHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Adapter to stop a packet capture",
|
"adapter_number": "Adapter to stop a packet capture",
|
||||||
"port_number": "Port on the adapter (always 0)"
|
"port_number": "Port on the adapter (always 0)"
|
||||||
},
|
},
|
||||||
@ -346,12 +326,11 @@ class VMwareHandler:
|
|||||||
yield from vm.stop_capture(adapter_number)
|
yield from vm.stop_capture(adapter_number)
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vmware/nodes/{node_id}/interfaces/vmnet",
|
r"/projects/{project_id}/vmware/nodes/{node_id}/interfaces/vmnet",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "VMnet interface allocated",
|
201: "VMnet interface allocated",
|
||||||
@ -366,3 +345,14 @@ class VMwareHandler:
|
|||||||
vm.vmnets.append(vmnet)
|
vm.vmnets.append(vmnet)
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json({"vmnet": vmnet})
|
response.json({"vmnet": vmnet})
|
||||||
|
|
||||||
|
@Route.get(
|
||||||
|
r"/vmware/vms",
|
||||||
|
status_codes={
|
||||||
|
200: "Success",
|
||||||
|
},
|
||||||
|
description="Get all VMware VMs available")
|
||||||
|
def get_vms(request, response):
|
||||||
|
vmware_manager = VMware.instance()
|
||||||
|
vms = yield from vmware_manager.list_vms()
|
||||||
|
response.json(vms)
|
||||||
|
@ -16,12 +16,15 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from aiohttp.web import HTTPConflict
|
from aiohttp.web import HTTPConflict
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....schemas.nio import NIO_SCHEMA
|
from gns3server.schemas.nio import NIO_SCHEMA
|
||||||
from ....schemas.vpcs import VPCS_CREATE_SCHEMA
|
from gns3server.compute.vpcs import VPCS
|
||||||
from ....schemas.vpcs import VPCS_UPDATE_SCHEMA
|
|
||||||
from ....schemas.vpcs import VPCS_OBJECT_SCHEMA
|
from gns3server.schemas.vpcs import (
|
||||||
from ....compute.vpcs import VPCS
|
VPCS_CREATE_SCHEMA,
|
||||||
|
VPCS_UPDATE_SCHEMA,
|
||||||
|
VPCS_OBJECT_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class VPCSHandler:
|
class VPCSHandler:
|
||||||
@ -30,11 +33,10 @@ class VPCSHandler:
|
|||||||
API entry points for VPCS.
|
API entry points for VPCS.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vpcs/nodes",
|
r"/projects/{project_id}/vpcs/nodes",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
201: "Instance created",
|
||||||
@ -47,20 +49,19 @@ class VPCSHandler:
|
|||||||
def create(request, response):
|
def create(request, response):
|
||||||
|
|
||||||
vpcs = VPCS.instance()
|
vpcs = VPCS.instance()
|
||||||
node = yield from vpcs.create_node(request.json["name"],
|
vm = yield from vpcs.create_node(request.json["name"],
|
||||||
request.match_info["project_id"],
|
request.match_info["project_id"],
|
||||||
request.json.get("node_id"),
|
request.json.get("node_id"),
|
||||||
console=request.json.get("console"),
|
console=request.json.get("console"),
|
||||||
startup_script=request.json.get("startup_script"))
|
startup_script=request.json.get("startup_script"))
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(node)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/vpcs/nodes/{node_id}",
|
r"/projects/{project_id}/vpcs/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Success",
|
200: "Success",
|
||||||
@ -75,12 +76,11 @@ class VPCSHandler:
|
|||||||
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}/vpcs/nodes/{node_id}",
|
r"/projects/{project_id}/vpcs/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Instance updated",
|
200: "Instance updated",
|
||||||
@ -100,12 +100,11 @@ class VPCSHandler:
|
|||||||
vm.startup_script = request.json.get("startup_script", vm.startup_script)
|
vm.startup_script = request.json.get("startup_script", vm.startup_script)
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/vpcs/nodes/{node_id}",
|
r"/projects/{project_id}/vpcs/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance deleted",
|
204: "Instance deleted",
|
||||||
@ -118,12 +117,11 @@ class VPCSHandler:
|
|||||||
yield from VPCS.instance().delete_node(request.match_info["node_id"])
|
yield from VPCS.instance().delete_node(request.match_info["node_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/start",
|
r"/projects/{project_id}/vpcs/nodes/{node_id}/start",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance started",
|
204: "Instance started",
|
||||||
@ -139,12 +137,11 @@ class VPCSHandler:
|
|||||||
yield from vm.start()
|
yield from vm.start()
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/stop",
|
r"/projects/{project_id}/vpcs/nodes/{node_id}/stop",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance stopped",
|
204: "Instance stopped",
|
||||||
@ -159,12 +156,11 @@ class VPCSHandler:
|
|||||||
yield from vm.stop()
|
yield from vm.stop()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/reload",
|
r"/projects/{project_id}/vpcs/nodes/{node_id}/reload",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Instance reloaded",
|
204: "Instance reloaded",
|
||||||
@ -182,8 +178,8 @@ class VPCSHandler:
|
|||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Network adapter where the nio is located",
|
"adapter_number": "Network adapter where the nio is located",
|
||||||
"port_number": "Port where the nio should be added"
|
"port_number": "Port where the nio should be added"
|
||||||
},
|
},
|
||||||
@ -207,12 +203,11 @@ class VPCSHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(nio)
|
response.json(nio)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the instance",
|
"node_id": "Node UUID",
|
||||||
"adapter_number": "Network adapter where the nio is located",
|
"adapter_number": "Network adapter where the nio is located",
|
||||||
"port_number": "Port from where the nio should be removed"
|
"port_number": "Port from where the nio should be removed"
|
||||||
},
|
},
|
||||||
|
@ -18,27 +18,24 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from aiohttp.web import HTTPForbidden
|
from aiohttp.web import HTTPForbidden
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....config import Config
|
from gns3server.config import Config
|
||||||
from ....compute.project_manager import ProjectManager
|
from gns3server.compute.project_manager import ProjectManager
|
||||||
from ....schemas.compute import COMPUTE_CREATE_SCHEMA, COMPUTE_OBJECT_SCHEMA
|
from gns3server.schemas.compute import COMPUTE_CREATE_SCHEMA, COMPUTE_OBJECT_SCHEMA
|
||||||
from ....controller import Controller
|
from gns3server.controller import Controller
|
||||||
from ....controller.compute import Compute
|
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ComputeHandler:
|
class ComputeHandler:
|
||||||
"""API entry points for compute management."""
|
"""API entry points for compute server management."""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/computes",
|
r"/computes",
|
||||||
description="Register a compute",
|
description="Register a compute server",
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Compute added"
|
201: "Compute server added"
|
||||||
},
|
},
|
||||||
input=COMPUTE_CREATE_SCHEMA,
|
input=COMPUTE_CREATE_SCHEMA,
|
||||||
output=COMPUTE_OBJECT_SCHEMA)
|
output=COMPUTE_OBJECT_SCHEMA)
|
||||||
@ -48,31 +45,29 @@ class ComputeHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(compute)
|
response.json(compute)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/computes",
|
r"/computes",
|
||||||
description="List compute nodes",
|
description="List of compute server",
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Compute list"
|
200: "Compute servers list returned"
|
||||||
})
|
})
|
||||||
def list(request, response):
|
def list(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
response.json([c for c in controller.computes.values()])
|
response.json([c for c in controller.computes.values()])
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/computes/shutdown",
|
r"/computes/shutdown",
|
||||||
description="Shutdown the local compute",
|
description="Shutdown a local compute server",
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Compute is shutting down",
|
201: "Compute server is shutting down",
|
||||||
403: "Compute shutdown refused"
|
403: "Compute server shutdown refused"
|
||||||
})
|
})
|
||||||
def shutdown(request, response):
|
def shutdown(request, response):
|
||||||
|
|
||||||
config = Config.instance()
|
config = Config.instance()
|
||||||
if config.get_section_config("Server").getboolean("local", False) is False:
|
if config.get_section_config("Server").getboolean("local", False) is False:
|
||||||
raise HTTPForbidden(text="You can only stop a local server")
|
raise HTTPForbidden(text="Only a local server can be shutdown")
|
||||||
|
|
||||||
# close all the projects first
|
# close all the projects first
|
||||||
pm = ProjectManager.instance()
|
pm = ProjectManager.instance()
|
||||||
@ -97,12 +92,12 @@ class ComputeHandler:
|
|||||||
asyncio.async(server.shutdown_server())
|
asyncio.async(server.shutdown_server())
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/computes/{compute_id:.+}",
|
r"/computes/{compute_id:.+}",
|
||||||
description="Get a compute node informations",
|
description="Get a compute server information",
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Compute list"
|
200: "Compute server information returned"
|
||||||
},
|
},
|
||||||
output=COMPUTE_OBJECT_SCHEMA)
|
output=COMPUTE_OBJECT_SCHEMA)
|
||||||
def get(request, response):
|
def get(request, response):
|
||||||
|
@ -17,9 +17,13 @@
|
|||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....schemas.link import LINK_OBJECT_SCHEMA, LINK_CAPTURE_SCHEMA
|
from gns3server.controller import Controller
|
||||||
from ....controller import Controller
|
|
||||||
|
from gns3server.schemas.link import (
|
||||||
|
LINK_OBJECT_SCHEMA,
|
||||||
|
LINK_CAPTURE_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LinkHandler:
|
class LinkHandler:
|
||||||
@ -27,11 +31,10 @@ class LinkHandler:
|
|||||||
API entry point for Link
|
API entry point for Link
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/links",
|
r"/projects/{project_id}/links",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Link created",
|
201: "Link created",
|
||||||
@ -51,12 +54,11 @@ class LinkHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(link)
|
response.json(link)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/links/{link_id}/start_capture",
|
r"/projects/{project_id}/links/{link_id}/start_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"link_id": "UUID of the link"
|
"link_id": "Link UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Capture started",
|
201: "Capture started",
|
||||||
@ -64,7 +66,7 @@ class LinkHandler:
|
|||||||
},
|
},
|
||||||
input=LINK_CAPTURE_SCHEMA,
|
input=LINK_CAPTURE_SCHEMA,
|
||||||
output=LINK_OBJECT_SCHEMA,
|
output=LINK_OBJECT_SCHEMA,
|
||||||
description="Start capture on a link instance. By default we consider it as an ethernet link")
|
description="Start capture on a link instance. By default we consider it as an Ethernet link")
|
||||||
def start_capture(request, response):
|
def start_capture(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
@ -74,12 +76,11 @@ class LinkHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(link)
|
response.json(link)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/links/{link_id}/stop_capture",
|
r"/projects/{project_id}/links/{link_id}/stop_capture",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"link_id": "UUID of the link"
|
"link_id": "Link UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Capture stopped",
|
201: "Capture stopped",
|
||||||
@ -95,12 +96,11 @@ class LinkHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(link)
|
response.json(link)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/links/{link_id}",
|
r"/projects/{project_id}/links/{link_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"link_id": "UUID of the link"
|
"link_id": "Link UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Link deleted",
|
204: "Link deleted",
|
||||||
@ -116,16 +116,15 @@ class LinkHandler:
|
|||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
response.json(link)
|
response.json(link)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/links/{link_id}/pcap",
|
r"/projects/{project_id}/links/{link_id}/pcap",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"link_id": "UUID of the link"
|
"link_id": "Link UUID"
|
||||||
},
|
},
|
||||||
description="Get the pcap from the capture",
|
description="Steam the pcap capture file",
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "Return the file",
|
200: "File returned",
|
||||||
403: "Permission denied",
|
403: "Permission denied",
|
||||||
404: "The file doesn't exist"
|
404: "The file doesn't exist"
|
||||||
})
|
})
|
||||||
@ -145,7 +144,7 @@ class LinkHandler:
|
|||||||
response.content_type = "application/vnd.tcpdump.pcap"
|
response.content_type = "application/vnd.tcpdump.pcap"
|
||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
response.enable_chunked_encoding()
|
response.enable_chunked_encoding()
|
||||||
# Very important: do not send a content length otherwise QT close the connection but curl can consume the Feed
|
# Very important: do not send a content length otherwise QT closes the connection (curl can consume the feed)
|
||||||
response.content_length = None
|
response.content_length = None
|
||||||
response.start(request)
|
response.start(request)
|
||||||
|
|
||||||
|
@ -15,9 +15,13 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....schemas.node import NODE_OBJECT_SCHEMA, NODE_UPDATE_SCHEMA
|
from gns3server.controller import Controller
|
||||||
from ....controller import Controller
|
|
||||||
|
from gns3server.schemas.node import (
|
||||||
|
NODE_OBJECT_SCHEMA,
|
||||||
|
NODE_UPDATE_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class NodeHandler:
|
class NodeHandler:
|
||||||
@ -25,11 +29,10 @@ class NodeHandler:
|
|||||||
API entry point for node
|
API entry point for node
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/nodes",
|
r"/projects/{project_id}/nodes",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
201: "Instance created",
|
||||||
@ -47,28 +50,27 @@ class NodeHandler:
|
|||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(node)
|
response.json(node)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/nodes",
|
r"/projects/{project_id}/nodes",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project"
|
"project_id": "Project UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "List of nodes",
|
200: "List of nodes returned",
|
||||||
},
|
},
|
||||||
description="List nodes of a project")
|
description="List nodes of a project")
|
||||||
def list_nodes(request, response):
|
def list_nodes(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
project = controller.get_project(request.match_info["project_id"])
|
||||||
response.json([ v for v in project.nodes.values() ])
|
response.json([v for v in project.nodes.values()])
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
r"/projects/{project_id}/nodes/{node_id}",
|
r"/projects/{project_id}/nodes/{node_id}",
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
200: "Instance updated",
|
||||||
400: "Invalid request"
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Update a node instance",
|
description="Update a node instance",
|
||||||
input=NODE_UPDATE_SCHEMA,
|
input=NODE_UPDATE_SCHEMA,
|
||||||
@ -77,25 +79,25 @@ class NodeHandler:
|
|||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
|
|
||||||
# Ignore this, because we use it only in create
|
# Ignore these because we only use them when creating a node
|
||||||
request.json.pop("node_id", None)
|
request.json.pop("node_id", None)
|
||||||
request.json.pop("node_type", None)
|
request.json.pop("node_type", None)
|
||||||
request.json.pop("compute_id", None)
|
request.json.pop("compute_id", None)
|
||||||
|
|
||||||
yield from node.update(**request.json)
|
yield from node.update(**request.json)
|
||||||
response.set_status(201)
|
response.set_status(200)
|
||||||
response.json(node)
|
response.json(node)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/nodes/{node_id}/start",
|
r"/projects/{project_id}/nodes/{node_id}/start",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the node"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
204: "Instance started",
|
||||||
400: "Invalid request"
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Start a node instance",
|
description="Start a node instance",
|
||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
@ -104,61 +106,58 @@ class NodeHandler:
|
|||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
yield from node.start()
|
yield from node.start()
|
||||||
response.set_status(201)
|
response.set_status(204)
|
||||||
response.json(node)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/nodes/{node_id}/stop",
|
r"/projects/{project_id}/nodes/{node_id}/stop",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the node"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
204: "Instance stopped",
|
||||||
400: "Invalid request"
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Start a node instance",
|
description="Stop a node instance",
|
||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def stop(request, response):
|
def stop(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
yield from node.stop()
|
yield from node.stop()
|
||||||
response.set_status(201)
|
response.set_status(204)
|
||||||
response.json(node)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/nodes/{node_id}/suspend",
|
r"/projects/{project_id}/nodes/{node_id}/suspend",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the node"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
204: "Instance suspended",
|
||||||
400: "Invalid request"
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Start a node instance",
|
description="Suspend a node instance",
|
||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def suspend(request, response):
|
def suspend(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
yield from node.suspend()
|
yield from node.suspend()
|
||||||
response.set_status(201)
|
response.set_status(204)
|
||||||
response.json(node)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/nodes/{node_id}/reload",
|
r"/projects/{project_id}/nodes/{node_id}/reload",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the node"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance created",
|
204: "Instance reloaded",
|
||||||
400: "Invalid request"
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Reload a node instance",
|
description="Reload a node instance",
|
||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
@ -167,23 +166,22 @@ class NodeHandler:
|
|||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
yield from node.reload()
|
yield from node.reload()
|
||||||
response.set_status(201)
|
response.set_status(204)
|
||||||
response.json(node)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}/nodes/{node_id}",
|
r"/projects/{project_id}/nodes/{node_id}",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "UUID for the project",
|
"project_id": "Project UUID",
|
||||||
"node_id": "UUID for the node"
|
"node_id": "Node UUID"
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
201: "Instance deleted",
|
204: "Instance deleted",
|
||||||
400: "Invalid request"
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
},
|
},
|
||||||
description="Delete a node instance")
|
description="Delete a node instance")
|
||||||
def delete(request, response):
|
def delete(request, response):
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
yield from node.destroy()
|
yield from node.destroy()
|
||||||
response.set_status(201)
|
response.set_status(204)
|
||||||
|
@ -19,10 +19,13 @@ import aiohttp
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....schemas.project import PROJECT_OBJECT_SCHEMA, PROJECT_CREATE_SCHEMA
|
from gns3server.controller import Controller
|
||||||
from ....controller import Controller
|
|
||||||
|
|
||||||
|
from gns3server.schemas.project import (
|
||||||
|
PROJECT_OBJECT_SCHEMA,
|
||||||
|
PROJECT_CREATE_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
@ -30,7 +33,6 @@ log = logging.getLogger()
|
|||||||
|
|
||||||
class ProjectHandler:
|
class ProjectHandler:
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects",
|
r"/projects",
|
||||||
description="Create a new project on the server",
|
description="Create a new project on the server",
|
||||||
@ -43,15 +45,13 @@ class ProjectHandler:
|
|||||||
def create_project(request, response):
|
def create_project(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
project = yield from controller.addProject(
|
project = yield from controller.add_project(name=request.json.get("name"),
|
||||||
name=request.json.get("name"),
|
path=request.json.get("path"),
|
||||||
path=request.json.get("path"),
|
project_id=request.json.get("project_id"),
|
||||||
project_id=request.json.get("project_id"),
|
temporary=request.json.get("temporary", False))
|
||||||
temporary=request.json.get("temporary", False))
|
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(project)
|
response.json(project)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects",
|
r"/projects",
|
||||||
description="List projects",
|
description="List projects",
|
||||||
@ -60,17 +60,16 @@ class ProjectHandler:
|
|||||||
})
|
})
|
||||||
def list_projects(request, response):
|
def list_projects(request, response):
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
response.json([ p for p in controller.projects.values() ])
|
response.json([p for p in controller.projects.values()])
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}",
|
r"/projects/{project_id}",
|
||||||
description="Get the project",
|
description="Get a project",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "The project exist",
|
200: "Project information returned",
|
||||||
404: "The project doesn't exist"
|
404: "The project doesn't exist"
|
||||||
})
|
})
|
||||||
def get(request, response):
|
def get(request, response):
|
||||||
@ -78,12 +77,11 @@ class ProjectHandler:
|
|||||||
project = controller.get_project(request.match_info["project_id"])
|
project = controller.get_project(request.match_info["project_id"])
|
||||||
response.json(project)
|
response.json(project)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/commit",
|
r"/projects/{project_id}/commit",
|
||||||
description="Write changes on disk",
|
description="Write changes on disk",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Changes have been written on disk",
|
204: "Changes have been written on disk",
|
||||||
@ -96,12 +94,11 @@ class ProjectHandler:
|
|||||||
yield from project.commit()
|
yield from project.commit()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/projects/{project_id}/close",
|
r"/projects/{project_id}/close",
|
||||||
description="Close a project",
|
description="Close a project",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "The project has been closed",
|
204: "The project has been closed",
|
||||||
@ -115,12 +112,11 @@ class ProjectHandler:
|
|||||||
controller.remove_project(project)
|
controller.remove_project(project)
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.delete(
|
@Route.delete(
|
||||||
r"/projects/{project_id}",
|
r"/projects/{project_id}",
|
||||||
description="Delete a project from disk",
|
description="Delete a project from disk",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
204: "Changes have been written on disk",
|
204: "Changes have been written on disk",
|
||||||
@ -134,12 +130,11 @@ class ProjectHandler:
|
|||||||
controller.remove_project(project)
|
controller.remove_project(project)
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/notifications",
|
r"/projects/{project_id}/notifications",
|
||||||
description="Receive notifications about the projects",
|
description="Receive notifications about projects",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "End of stream",
|
200: "End of stream",
|
||||||
@ -153,7 +148,7 @@ class ProjectHandler:
|
|||||||
response.content_type = "application/json"
|
response.content_type = "application/json"
|
||||||
response.set_status(200)
|
response.set_status(200)
|
||||||
response.enable_chunked_encoding()
|
response.enable_chunked_encoding()
|
||||||
# Very important: do not send a content lenght otherwise QT close the connection but curl can consume the Feed
|
# Very important: do not send a content length otherwise QT closes the connection (curl can consume the feed)
|
||||||
response.content_length = None
|
response.content_length = None
|
||||||
|
|
||||||
response.start(request)
|
response.start(request)
|
||||||
@ -165,12 +160,11 @@ class ProjectHandler:
|
|||||||
except asyncio.futures.CancelledError as e:
|
except asyncio.futures.CancelledError as e:
|
||||||
break
|
break
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}/notifications/ws",
|
r"/projects/{project_id}/notifications/ws",
|
||||||
description="Receive notifications about the projects via Websocket",
|
description="Receive notifications about projects from a Websocket",
|
||||||
parameters={
|
parameters={
|
||||||
"project_id": "The UUID of the project",
|
"project_id": "Project UUID",
|
||||||
},
|
},
|
||||||
status_codes={
|
status_codes={
|
||||||
200: "End of stream",
|
200: "End of stream",
|
||||||
@ -187,8 +181,8 @@ class ProjectHandler:
|
|||||||
with project.queue() as queue:
|
with project.queue() as queue:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
notif = yield from queue.get_json(5)
|
notification = yield from queue.get_json(5)
|
||||||
except asyncio.futures.CancelledError as e:
|
except asyncio.futures.CancelledError as e:
|
||||||
break
|
break
|
||||||
ws.send_str(notif)
|
ws.send_str(notification)
|
||||||
return ws
|
return ws
|
||||||
|
@ -15,16 +15,15 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from ....web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ....config import Config
|
from gns3server.config import Config
|
||||||
from ....schemas.version import VERSION_SCHEMA
|
from gns3server.schemas.version import VERSION_SCHEMA
|
||||||
from ....version import __version__
|
from gns3server.version import __version__
|
||||||
from aiohttp.web import HTTPConflict
|
from aiohttp.web import HTTPConflict
|
||||||
|
|
||||||
|
|
||||||
class VersionHandler:
|
class VersionHandler:
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/version",
|
r"/version",
|
||||||
description="Retrieve the server version number",
|
description="Retrieve the server version number",
|
||||||
@ -35,7 +34,6 @@ class VersionHandler:
|
|||||||
local_server = config.get_section_config("Server").getboolean("local", False)
|
local_server = config.get_section_config("Server").getboolean("local", False)
|
||||||
response.json({"version": __version__, "local": local_server})
|
response.json({"version": __version__, "local": local_server})
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/version",
|
r"/version",
|
||||||
description="Check if version is the same as the server",
|
description="Check if version is the same as the server",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2015 GNS3 Technologies Inc.
|
# Copyright (C) 2016 GNS3 Technologies Inc.
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
@ -15,58 +15,51 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
from ..web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ..controller import Controller
|
from gns3server.controller import Controller
|
||||||
from ..compute.port_manager import PortManager
|
from gns3server.compute.port_manager import PortManager
|
||||||
from ..compute.project_manager import ProjectManager
|
from gns3server.compute.project_manager import ProjectManager
|
||||||
from ..version import __version__
|
from gns3server.version import __version__
|
||||||
|
|
||||||
|
|
||||||
class IndexHandler:
|
class IndexHandler:
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/",
|
r"/",
|
||||||
description="Home page for GNS3Server"
|
description="Home page of the GNS3 server"
|
||||||
)
|
)
|
||||||
def index(request, response):
|
def index(request, response):
|
||||||
response.template("index.html")
|
response.template("index.html")
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/compute",
|
r"/compute",
|
||||||
description="Ressources used by GNS3 Compute"
|
description="Resources used by the GNS3 compute servers"
|
||||||
)
|
)
|
||||||
def compute(request, response):
|
def compute(request, response):
|
||||||
response.template("compute.html",
|
response.template("compute.html",
|
||||||
port_manager=PortManager.instance(),
|
port_manager=PortManager.instance(),
|
||||||
project_manager=ProjectManager.instance()
|
project_manager=ProjectManager.instance())
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/controller",
|
r"/controller",
|
||||||
description="Ressources used by GNS3 Controller"
|
description="Resources used by the GNS3 controller server"
|
||||||
)
|
)
|
||||||
def controller(request, response):
|
def controller(request, response):
|
||||||
response.template("controller.html",
|
response.template("controller.html",
|
||||||
controller=Controller.instance()
|
controller=Controller.instance())
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/projects/{project_id}",
|
r"/projects/{project_id}",
|
||||||
description="Ressources used by GNS3 Controller"
|
description="List of the GNS3 projects"
|
||||||
)
|
)
|
||||||
def project(request, response):
|
def project(request, response):
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
response.template("project.html",
|
response.template("project.html",
|
||||||
project=controller.get_project(request.match_info["project_id"]))
|
project=controller.get_project(request.match_info["project_id"]))
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/v1/version",
|
r"/v1/version",
|
||||||
description="Old API"
|
description="Old 1.0 API"
|
||||||
)
|
)
|
||||||
def get_v1(request, response):
|
def get_v1(request, response):
|
||||||
response.json({"version": __version__})
|
response.json({"version": __version__})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2015 GNS3 Technologies Inc.
|
# Copyright (C) 2016 GNS3 Technologies Inc.
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
@ -22,17 +22,16 @@ import io
|
|||||||
import tarfile
|
import tarfile
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from ..config import Config
|
from gns3server.config import Config
|
||||||
from ..web.route import Route
|
from gns3server.web.route import Route
|
||||||
from ..utils.images import remove_checksum, md5sum
|
from gns3server.utils.images import remove_checksum, md5sum
|
||||||
|
|
||||||
|
|
||||||
class UploadHandler:
|
class UploadHandler:
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/upload",
|
r"/upload",
|
||||||
description="Manage upload of GNS3 images",
|
description="List binary images",
|
||||||
api_version=None
|
api_version=None
|
||||||
)
|
)
|
||||||
def index(request, response):
|
def index(request, response):
|
||||||
@ -50,10 +49,9 @@ class UploadHandler:
|
|||||||
uploaded_files.append(iourc_path)
|
uploaded_files.append(iourc_path)
|
||||||
response.template("upload.html", files=uploaded_files)
|
response.template("upload.html", files=uploaded_files)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
r"/upload",
|
r"/upload",
|
||||||
description="Manage upload of GNS3 images",
|
description="Upload binary images",
|
||||||
api_version=None
|
api_version=None
|
||||||
)
|
)
|
||||||
def upload(request, response):
|
def upload(request, response):
|
||||||
@ -95,16 +93,14 @@ class UploadHandler:
|
|||||||
return
|
return
|
||||||
response.redirect("/upload")
|
response.redirect("/upload")
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/backup/images.tar",
|
r"/backup/images.tar",
|
||||||
description="Backup GNS3 images",
|
description="Backup binary images",
|
||||||
api_version=None
|
api_version=None
|
||||||
)
|
)
|
||||||
def backup_images(request, response):
|
def backup_images(request, response):
|
||||||
yield from UploadHandler._backup_directory(request, response, UploadHandler.image_directory())
|
yield from UploadHandler._backup_directory(request, response, UploadHandler.image_directory())
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@Route.get(
|
@Route.get(
|
||||||
r"/backup/projects.tar",
|
r"/backup/projects.tar",
|
||||||
description="Backup GNS3 projects",
|
description="Backup GNS3 projects",
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
NODE_LIST_IMAGES_SCHEMA = {
|
NODE_LIST_IMAGES_SCHEMA = {
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"description": "List of disk images",
|
"description": "List of binary images",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
|
@ -71,7 +71,7 @@ def test_vboxmanage_path(manager, tmpdir):
|
|||||||
assert manager.find_vboxmanage() == path
|
assert manager.find_vboxmanage() == path
|
||||||
|
|
||||||
|
|
||||||
def test_list_images(manager, loop):
|
def test_list_vms(manager, loop):
|
||||||
vm_list = ['"Windows 8.1" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
vm_list = ['"Windows 8.1" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
||||||
'"Carriage',
|
'"Carriage',
|
||||||
'Return" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
'Return" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
||||||
@ -92,7 +92,7 @@ def test_list_images(manager, loop):
|
|||||||
|
|
||||||
with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute") as mock:
|
with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute") as mock:
|
||||||
mock.side_effect = execute_mock
|
mock.side_effect = execute_mock
|
||||||
vms = loop.run_until_complete(asyncio.async(manager.list_images()))
|
vms = loop.run_until_complete(asyncio.async(manager.list_vms()))
|
||||||
assert vms == [
|
assert vms == [
|
||||||
{"vmname": "Windows 8.1", "ram": 512},
|
{"vmname": "Windows 8.1", "ram": 512},
|
||||||
{"vmname": "Linux Microcore 4.7.1", "ram": 256}
|
{"vmname": "Linux Microcore 4.7.1", "ram": 256}
|
||||||
|
@ -121,18 +121,18 @@ def test_addProject(controller, async_run):
|
|||||||
uuid1 = str(uuid.uuid4())
|
uuid1 = str(uuid.uuid4())
|
||||||
uuid2 = str(uuid.uuid4())
|
uuid2 = str(uuid.uuid4())
|
||||||
|
|
||||||
async_run(controller.addProject(project_id=uuid1))
|
async_run(controller.add_project(project_id=uuid1))
|
||||||
assert len(controller.projects) == 1
|
assert len(controller.projects) == 1
|
||||||
async_run(controller.addProject(project_id=uuid1))
|
async_run(controller.add_project(project_id=uuid1))
|
||||||
assert len(controller.projects) == 1
|
assert len(controller.projects) == 1
|
||||||
async_run(controller.addProject(project_id=uuid2))
|
async_run(controller.add_project(project_id=uuid2))
|
||||||
assert len(controller.projects) == 2
|
assert len(controller.projects) == 2
|
||||||
|
|
||||||
|
|
||||||
def test_remove_project(controller, async_run):
|
def test_remove_project(controller, async_run):
|
||||||
uuid1 = str(uuid.uuid4())
|
uuid1 = str(uuid.uuid4())
|
||||||
|
|
||||||
project1 = async_run(controller.addProject(project_id=uuid1))
|
project1 = async_run(controller.add_project(project_id=uuid1))
|
||||||
assert len(controller.projects) == 1
|
assert len(controller.projects) == 1
|
||||||
|
|
||||||
controller.remove_project(project1)
|
controller.remove_project(project1)
|
||||||
@ -146,13 +146,13 @@ def test_addProject_with_compute(controller, async_run):
|
|||||||
compute.post = MagicMock()
|
compute.post = MagicMock()
|
||||||
controller._computes = {"test1": compute}
|
controller._computes = {"test1": compute}
|
||||||
|
|
||||||
project1 = async_run(controller.addProject(project_id=uuid1))
|
project1 = async_run(controller.add_project(project_id=uuid1))
|
||||||
|
|
||||||
|
|
||||||
def test_getProject(controller, async_run):
|
def test_getProject(controller, async_run):
|
||||||
uuid1 = str(uuid.uuid4())
|
uuid1 = str(uuid.uuid4())
|
||||||
|
|
||||||
project = async_run(controller.addProject(project_id=uuid1))
|
project = async_run(controller.add_project(project_id=uuid1))
|
||||||
assert controller.get_project(uuid1) == project
|
assert controller.get_project(uuid1) == project
|
||||||
with pytest.raises(aiohttp.web.HTTPNotFound):
|
with pytest.raises(aiohttp.web.HTTPNotFound):
|
||||||
assert controller.get_project("dsdssd")
|
assert controller.get_project("dsdssd")
|
||||||
|
@ -96,9 +96,16 @@ def test_docker_delete(http_compute, vm):
|
|||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
def test_docker_reload(http_compute, vm):
|
def test_docker_pause(http_compute, vm):
|
||||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.pause", return_value=True) as mock:
|
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.pause", return_value=True) as mock:
|
||||||
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]))
|
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/pause".format(project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||||
|
assert mock.called
|
||||||
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
|
def test_docker_unpause(http_compute, vm):
|
||||||
|
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.unpause", return_value=True) as mock:
|
||||||
|
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/unpause".format(project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||||
assert mock.called
|
assert mock.called
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
|
@ -151,17 +151,17 @@ def fake_file(tmpdir):
|
|||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
def test_vms(http_compute, tmpdir, fake_dynamips, fake_file):
|
def test_images(http_compute, tmpdir, fake_dynamips, fake_file):
|
||||||
|
|
||||||
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir), example=True):
|
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir), example=True):
|
||||||
response = http_compute.get("/dynamips/nodes")
|
response = http_compute.get("/dynamips/images")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.json == [{"filename": "7200.bin", "path": "7200.bin"}]
|
assert response.json == [{"filename": "7200.bin", "path": "7200.bin"}]
|
||||||
|
|
||||||
|
|
||||||
def test_upload_vm(http_compute, tmpdir):
|
def test_upload_image(http_compute, tmpdir):
|
||||||
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir),):
|
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir),):
|
||||||
response = http_compute.post("/dynamips/nodes/test2", body="TEST", raw=True)
|
response = http_compute.post("/dynamips/images/test2", body="TEST", raw=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
with open(str(tmpdir / "test2")) as f:
|
with open(str(tmpdir / "test2")) as f:
|
||||||
@ -172,11 +172,11 @@ def test_upload_vm(http_compute, tmpdir):
|
|||||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||||
|
|
||||||
|
|
||||||
def test_upload_vm_permission_denied(http_compute, tmpdir):
|
def test_upload_image_permission_denied(http_compute, tmpdir):
|
||||||
with open(str(tmpdir / "test2.tmp"), "w+") as f:
|
with open(str(tmpdir / "test2.tmp"), "w+") as f:
|
||||||
f.write("")
|
f.write("")
|
||||||
os.chmod(str(tmpdir / "test2.tmp"), 0)
|
os.chmod(str(tmpdir / "test2.tmp"), 0)
|
||||||
|
|
||||||
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir),):
|
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir),):
|
||||||
response = http_compute.post("/dynamips/nodes/test2", body="TEST", raw=True)
|
response = http_compute.post("/dynamips/images/test2", body="TEST", raw=True)
|
||||||
assert response.status == 409
|
assert response.status == 409
|
||||||
|
@ -328,17 +328,17 @@ def test_get_configs_with_startup_config_file(http_compute, project, vm):
|
|||||||
assert response.json["startup_config_content"] == "TEST"
|
assert response.json["startup_config_content"] == "TEST"
|
||||||
|
|
||||||
|
|
||||||
def test_vms(http_compute, tmpdir, fake_iou_bin):
|
def test_images(http_compute, tmpdir, fake_iou_bin):
|
||||||
|
|
||||||
with patch("gns3server.compute.IOU.get_images_directory", return_value=str(tmpdir)):
|
with patch("gns3server.compute.IOU.get_images_directory", return_value=str(tmpdir)):
|
||||||
response = http_compute.get("/iou/nodes", example=True)
|
response = http_compute.get("/iou/images", example=True)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.json == [{"filename": "iou.bin", "path": "iou.bin"}]
|
assert response.json == [{"filename": "iou.bin", "path": "iou.bin"}]
|
||||||
|
|
||||||
|
|
||||||
def test_upload_vm(http_compute, tmpdir):
|
def test_image_vm(http_compute, tmpdir):
|
||||||
with patch("gns3server.compute.IOU.get_images_directory", return_value=str(tmpdir),):
|
with patch("gns3server.compute.IOU.get_images_directory", return_value=str(tmpdir),):
|
||||||
response = http_compute.post("/iou/nodes/test2", body="TEST", raw=True)
|
response = http_compute.post("/iou/images/test2", body="TEST", raw=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
with open(str(tmpdir / "test2")) as f:
|
with open(str(tmpdir / "test2")) as f:
|
||||||
|
@ -224,16 +224,16 @@ def test_qemu_list_binaries_filter(http_compute, vm):
|
|||||||
assert response.json == ret
|
assert response.json == ret
|
||||||
|
|
||||||
|
|
||||||
def test_vms(http_compute, tmpdir, fake_qemu_vm):
|
def test_images(http_compute, tmpdir, fake_qemu_vm):
|
||||||
|
|
||||||
response = http_compute.get("/qemu/nodes")
|
response = http_compute.get("/qemu/images")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.json == [{"filename": "linux载.img", "path": "linux载.img"}]
|
assert response.json == [{"filename": "linux载.img", "path": "linux载.img"}]
|
||||||
|
|
||||||
|
|
||||||
def test_upload_vm(http_compute, tmpdir):
|
def test_upload_image(http_compute, tmpdir):
|
||||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
||||||
response = http_compute.post("/qemu/nodes/test2", body="TEST", raw=True)
|
response = http_compute.post("/qemu/images/test2", body="TEST", raw=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
with open(str(tmpdir / "test2")) as f:
|
with open(str(tmpdir / "test2")) as f:
|
||||||
@ -244,9 +244,9 @@ def test_upload_vm(http_compute, tmpdir):
|
|||||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||||
|
|
||||||
|
|
||||||
def test_upload_vm_ova(http_compute, tmpdir):
|
def test_upload_image_ova(http_compute, tmpdir):
|
||||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
||||||
response = http_compute.post("/qemu/nodes/test2.ova/test2.vmdk", body="TEST", raw=True)
|
response = http_compute.post("/qemu/images/test2.ova/test2.vmdk", body="TEST", raw=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
with open(str(tmpdir / "test2.ova" / "test2.vmdk")) as f:
|
with open(str(tmpdir / "test2.ova" / "test2.vmdk")) as f:
|
||||||
@ -257,19 +257,19 @@ def test_upload_vm_ova(http_compute, tmpdir):
|
|||||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||||
|
|
||||||
|
|
||||||
def test_upload_vm_forbiden_location(http_compute, tmpdir):
|
def test_upload_image_forbiden_location(http_compute, tmpdir):
|
||||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
||||||
response = http_compute.post("/qemu/nodes/../../test2", body="TEST", raw=True)
|
response = http_compute.post("/qemu/images/../../test2", body="TEST", raw=True)
|
||||||
assert response.status == 403
|
assert response.status == 403
|
||||||
|
|
||||||
|
|
||||||
def test_upload_vm_permission_denied(http_compute, tmpdir):
|
def test_upload_image_permission_denied(http_compute, tmpdir):
|
||||||
with open(str(tmpdir / "test2.tmp"), "w+") as f:
|
with open(str(tmpdir / "test2.tmp"), "w+") as f:
|
||||||
f.write("")
|
f.write("")
|
||||||
os.chmod(str(tmpdir / "test2.tmp"), 0)
|
os.chmod(str(tmpdir / "test2.tmp"), 0)
|
||||||
|
|
||||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
||||||
response = http_compute.post("/qemu/nodes/test2", body="TEST", raw=True)
|
response = http_compute.post("/qemu/images/test2", body="TEST", raw=True)
|
||||||
assert response.status == 409
|
assert response.status == 409
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ def compute(http_controller, async_run):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def project(http_controller, async_run):
|
def project(http_controller, async_run):
|
||||||
return async_run(Controller.instance().addProject())
|
return async_run(Controller.instance().add_project())
|
||||||
|
|
||||||
|
|
||||||
def test_create_link(http_controller, tmpdir, project, compute, async_run):
|
def test_create_link(http_controller, tmpdir, project, compute, async_run):
|
||||||
|
@ -44,7 +44,7 @@ def compute(http_controller, async_run):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def project(http_controller, async_run):
|
def project(http_controller, async_run):
|
||||||
return async_run(Controller.instance().addProject())
|
return async_run(Controller.instance().add_project())
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -103,7 +103,7 @@ def test_update_node(http_controller, tmpdir, project, compute, node):
|
|||||||
"startup_script": "echo test"
|
"startup_script": "echo test"
|
||||||
}
|
}
|
||||||
}, example=True)
|
}, example=True)
|
||||||
assert response.status == 201
|
assert response.status == 200
|
||||||
assert response.json["name"] == "test"
|
assert response.json["name"] == "test"
|
||||||
assert "name" not in response.json["properties"]
|
assert "name" not in response.json["properties"]
|
||||||
|
|
||||||
@ -113,17 +113,14 @@ def test_start_node(http_controller, tmpdir, project, compute, node):
|
|||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
|
|
||||||
response = http_controller.post("/projects/{}/nodes/{}/start".format(project.id, node.id), example=True)
|
response = http_controller.post("/projects/{}/nodes/{}/start".format(project.id, node.id), example=True)
|
||||||
assert response.status == 201
|
assert response.status == 204
|
||||||
assert response.json["name"] == node.name
|
|
||||||
|
|
||||||
|
|
||||||
def test_stop_node(http_controller, tmpdir, project, compute, node):
|
def test_stop_node(http_controller, tmpdir, project, compute, node):
|
||||||
response = MagicMock()
|
response = MagicMock()
|
||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
|
|
||||||
response = http_controller.post("/projects/{}/nodes/{}/stop".format(project.id, node.id), example=True)
|
response = http_controller.post("/projects/{}/nodes/{}/stop".format(project.id, node.id), example=True)
|
||||||
assert response.status == 201
|
assert response.status == 204
|
||||||
assert response.json["name"] == node.name
|
|
||||||
|
|
||||||
|
|
||||||
def test_suspend_node(http_controller, tmpdir, project, compute, node):
|
def test_suspend_node(http_controller, tmpdir, project, compute, node):
|
||||||
@ -131,8 +128,7 @@ def test_suspend_node(http_controller, tmpdir, project, compute, node):
|
|||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
|
|
||||||
response = http_controller.post("/projects/{}/nodes/{}/suspend".format(project.id, node.id), example=True)
|
response = http_controller.post("/projects/{}/nodes/{}/suspend".format(project.id, node.id), example=True)
|
||||||
assert response.status == 201
|
assert response.status == 204
|
||||||
assert response.json["name"] == node.name
|
|
||||||
|
|
||||||
|
|
||||||
def test_reload_node(http_controller, tmpdir, project, compute, node):
|
def test_reload_node(http_controller, tmpdir, project, compute, node):
|
||||||
@ -140,8 +136,7 @@ def test_reload_node(http_controller, tmpdir, project, compute, node):
|
|||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
|
|
||||||
response = http_controller.post("/projects/{}/nodes/{}/reload".format(project.id, node.id), example=True)
|
response = http_controller.post("/projects/{}/nodes/{}/reload".format(project.id, node.id), example=True)
|
||||||
assert response.status == 201
|
assert response.status == 204
|
||||||
assert response.json["name"] == node.name
|
|
||||||
|
|
||||||
|
|
||||||
def test_delete_node(http_controller, tmpdir, project, compute, node):
|
def test_delete_node(http_controller, tmpdir, project, compute, node):
|
||||||
@ -149,4 +144,4 @@ def test_delete_node(http_controller, tmpdir, project, compute, node):
|
|||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
|
|
||||||
response = http_controller.delete("/projects/{}/nodes/{}".format(project.id, node.id), example=True)
|
response = http_controller.delete("/projects/{}/nodes/{}".format(project.id, node.id), example=True)
|
||||||
assert response.status == 201
|
assert response.status == 204
|
||||||
|
@ -33,7 +33,7 @@ def test_index(http_root):
|
|||||||
|
|
||||||
|
|
||||||
def test_controller(http_root, async_run):
|
def test_controller(http_root, async_run):
|
||||||
project = async_run(Controller.instance().addProject(name="test"))
|
project = async_run(Controller.instance().add_project(name="test"))
|
||||||
response = http_root.get('/controller')
|
response = http_root.get('/controller')
|
||||||
assert "test" in response.html
|
assert "test" in response.html
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
@ -45,7 +45,7 @@ def test_compute(http_root):
|
|||||||
|
|
||||||
|
|
||||||
def test_project(http_root, async_run):
|
def test_project(http_root, async_run):
|
||||||
project = async_run(Controller.instance().addProject(name="test"))
|
project = async_run(Controller.instance().add_project(name="test"))
|
||||||
response = http_root.get('/projects/{}'.format(project.id))
|
response = http_root.get('/projects/{}'.format(project.id))
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user