mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 14:01:15 +02:00
Handlers: cleanup and fixes.
This commit is contained in:
1 parent
885d93be02
commit
f81d35cc29
33 files changed
+723
-766
No files matched your search
@@ -22,7 +22,6 @@ Docker server module.
|
||||
import asyncio
|
||||
import logging
|
||||
import aiohttp
|
||||
import urllib
|
||||
import json
|
||||
from gns3server.utils import parse_version
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ class VirtualBox(BaseManager):
|
||||
continue
|
||||
|
||||
@asyncio.coroutine
|
||||
def list_images(self):
|
||||
def list_vms(self):
|
||||
"""
|
||||
Gets VirtualBox VM list.
|
||||
"""
|
||||
|
||||
@@ -31,7 +31,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Controller:
|
||||
"""The controller manage multiple gns3 computes"""
|
||||
"""The controller manage multiple gns3 compute servers"""
|
||||
|
||||
def __init__(self):
|
||||
self._computes = {}
|
||||
@@ -97,7 +97,7 @@ class Controller:
|
||||
|
||||
# We disallow to create from the outside the
|
||||
if compute_id == 'local':
|
||||
return self._createLocalCompute()
|
||||
return self._create_local_compute()
|
||||
|
||||
if compute_id not in self._computes:
|
||||
compute = Compute(compute_id=compute_id, controller=self, **kwargs)
|
||||
@@ -105,7 +105,7 @@ class Controller:
|
||||
self.save()
|
||||
return self._computes[compute_id]
|
||||
|
||||
def _createLocalCompute(self):
|
||||
def _create_local_compute(self):
|
||||
"""
|
||||
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))
|
||||
|
||||
@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
|
||||
|
||||
|
||||
@@ -17,16 +17,15 @@
|
||||
|
||||
from aiohttp.web import HTTPForbidden
|
||||
|
||||
from ....web.route import Route
|
||||
from ....config import Config
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.config import Config
|
||||
|
||||
|
||||
class ConfigHandler:
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/config/reload",
|
||||
description="Check if version is the same as the server",
|
||||
description="Reload the server configuration file",
|
||||
status_codes={
|
||||
201: "Config reload",
|
||||
403: "Config reload refused"
|
||||
@@ -35,6 +34,6 @@ class ConfigHandler:
|
||||
|
||||
config = Config.instance()
|
||||
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()
|
||||
response.set_status(201)
|
||||
@@ -18,40 +18,26 @@
|
||||
import os
|
||||
from aiohttp.web import HTTPConflict
|
||||
|
||||
from ....web.route import Route
|
||||
from ....compute.docker import Docker
|
||||
from gns3server.web.route import Route
|
||||
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_OBJECT_SCHEMA,
|
||||
DOCKER_UPDATE_SCHEMA,
|
||||
DOCKER_LIST_IMAGES_SCHEMA
|
||||
)
|
||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
||||
from ....schemas.nio import NIO_SCHEMA
|
||||
|
||||
|
||||
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(
|
||||
r"/projects/{project_id}/docker/nodes",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
@@ -63,33 +49,32 @@ class DockerHandler:
|
||||
output=DOCKER_OBJECT_SCHEMA)
|
||||
def create(request, response):
|
||||
docker_manager = Docker.instance()
|
||||
vm = yield from docker_manager.create_node(request.json.pop("name"),
|
||||
request.match_info["project_id"],
|
||||
request.json.get("node_id"),
|
||||
image=request.json.pop("image"),
|
||||
start_command=request.json.get("start_command"),
|
||||
environment=request.json.get("environment"),
|
||||
adapters=request.json.get("adapters"),
|
||||
console=request.json.get("console"),
|
||||
console_type=request.json.get("console_type"),
|
||||
console_resolution=request.json.get("console_resolution", "1024x768"),
|
||||
console_http_port=request.json.get("console_http_port", 80),
|
||||
console_http_path=request.json.get("console_http_path", "/"),
|
||||
aux=request.json.get("aux"))
|
||||
container = yield from docker_manager.create_node(request.json.pop("name"),
|
||||
request.match_info["project_id"],
|
||||
request.json.get("node_id"),
|
||||
image=request.json.pop("image"),
|
||||
start_command=request.json.get("start_command"),
|
||||
environment=request.json.get("environment"),
|
||||
adapters=request.json.get("adapters"),
|
||||
console=request.json.get("console"),
|
||||
console_type=request.json.get("console_type"),
|
||||
console_resolution=request.json.get("console_resolution", "1024x768"),
|
||||
console_http_port=request.json.get("console_http_port", 80),
|
||||
console_http_path=request.json.get("console_http_path", "/"),
|
||||
aux=request.json.get("aux"))
|
||||
for name, value in request.json.items():
|
||||
if name != "_node_id":
|
||||
if hasattr(vm, name) and getattr(vm, name) != value:
|
||||
setattr(vm, name, value)
|
||||
if name != "node_id":
|
||||
if hasattr(container, name) and getattr(container, name) != value:
|
||||
setattr(container, name, value)
|
||||
|
||||
response.set_status(201)
|
||||
response.json(vm)
|
||||
response.json(container)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}/start",
|
||||
parameters={
|
||||
"project_id": "UUID of the project",
|
||||
"node_id": "ID of the container"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance started",
|
||||
@@ -101,16 +86,15 @@ class DockerHandler:
|
||||
output=DOCKER_OBJECT_SCHEMA)
|
||||
def start(request, response):
|
||||
docker_manager = Docker.instance()
|
||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from vm.start()
|
||||
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from container.start()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}/stop",
|
||||
parameters={
|
||||
"project_id": "UUID of the project",
|
||||
"node_id": "ID of the container"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance stopped",
|
||||
@@ -122,16 +106,15 @@ class DockerHandler:
|
||||
output=DOCKER_OBJECT_SCHEMA)
|
||||
def stop(request, response):
|
||||
docker_manager = Docker.instance()
|
||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from vm.stop()
|
||||
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from container.stop()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}/reload",
|
||||
parameters={
|
||||
"project_id": "UUID of the project",
|
||||
"node_id": "ID of the container"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance restarted",
|
||||
@@ -143,16 +126,15 @@ class DockerHandler:
|
||||
output=DOCKER_OBJECT_SCHEMA)
|
||||
def reload(request, response):
|
||||
docker_manager = Docker.instance()
|
||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from vm.restart()
|
||||
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from container.restart()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "ID for the container",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance deleted",
|
||||
@@ -162,16 +144,15 @@ class DockerHandler:
|
||||
description="Delete a Docker container")
|
||||
def delete(request, response):
|
||||
docker_manager = Docker.instance()
|
||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from vm.delete()
|
||||
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from container.delete()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}/suspend",
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}/pause",
|
||||
parameters={
|
||||
"project_id": "UUID of the project",
|
||||
"node_id": "ID of the container"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance paused",
|
||||
@@ -181,17 +162,37 @@ class DockerHandler:
|
||||
description="Pause a Docker container",
|
||||
input=DOCKER_CREATE_SCHEMA,
|
||||
output=DOCKER_OBJECT_SCHEMA)
|
||||
def suspend(request, response):
|
||||
def pause(request, response):
|
||||
docker_manager = Docker.instance()
|
||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from vm.pause()
|
||||
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
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)
|
||||
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "ID of the container",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter where the nio should be added",
|
||||
"port_number": "Port on the adapter"
|
||||
},
|
||||
@@ -205,21 +206,20 @@ class DockerHandler:
|
||||
output=NIO_SCHEMA)
|
||||
def create_nio(request, response):
|
||||
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"]
|
||||
if nio_type not in ("nio_udp"):
|
||||
if nio_type != "nio_udp":
|
||||
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)
|
||||
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.json(nio)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "ID of the container",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter where the nio should be added",
|
||||
"port_number": "Port on the adapter"
|
||||
},
|
||||
@@ -231,16 +231,15 @@ class DockerHandler:
|
||||
description="Remove a NIO from a Docker container")
|
||||
def delete_nio(request, response):
|
||||
docker_manager = Docker.instance()
|
||||
vm = 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"]))
|
||||
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
yield from container.adapter_remove_nio_binding(int(request.match_info["adapter_number"]))
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.put(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance updated",
|
||||
@@ -254,25 +253,25 @@ class DockerHandler:
|
||||
def update(request, response):
|
||||
|
||||
docker_manager = Docker.instance()
|
||||
vm = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
vm.name = request.json.get("name", vm.name)
|
||||
vm.console = request.json.get("console", vm.console)
|
||||
vm.aux = request.json.get("aux", vm.aux)
|
||||
vm.console_type = request.json.get("console_type", vm.console_type)
|
||||
vm.console_resolution = request.json.get("console_resolution", vm.console_resolution)
|
||||
vm.console_http_port = request.json.get("console_http_port", vm.console_http_port)
|
||||
vm.console_http_path = request.json.get("console_http_path", vm.console_http_path)
|
||||
vm.start_command = request.json.get("start_command", vm.start_command)
|
||||
vm.environment = request.json.get("environment", vm.environment)
|
||||
vm.adapters = request.json.get("adapters", vm.adapters)
|
||||
yield from vm.update()
|
||||
response.json(vm)
|
||||
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
container.name = request.json.get("name", container.name)
|
||||
container.console = request.json.get("console", container.console)
|
||||
container.aux = request.json.get("aux", container.aux)
|
||||
container.console_type = request.json.get("console_type", container.console_type)
|
||||
container.console_resolution = request.json.get("console_resolution", container.console_resolution)
|
||||
container.console_http_port = request.json.get("console_http_port", container.console_http_port)
|
||||
container.console_http_path = request.json.get("console_http_path", container.console_http_path)
|
||||
container.start_command = request.json.get("start_command", container.start_command)
|
||||
container.environment = request.json.get("environment", container.environment)
|
||||
container.adapters = request.json.get("adapters", container.adapters)
|
||||
yield from container.update()
|
||||
response.json(container)
|
||||
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to start a packet capture",
|
||||
"port_number": "Port on the adapter"
|
||||
},
|
||||
@@ -282,25 +281,25 @@ class DockerHandler:
|
||||
404: "Instance doesn't exist",
|
||||
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)
|
||||
def start_capture(request, response):
|
||||
|
||||
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"])
|
||||
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():
|
||||
raise HTTPConflict(text="Cannot capture traffic on a non started VM")
|
||||
yield from vm.start_capture(adapter_number, pcap_file_path)
|
||||
if not container.is_running():
|
||||
raise HTTPConflict(text="Cannot capture traffic on a non started Docker container")
|
||||
yield from container.start_capture(adapter_number, pcap_file_path)
|
||||
response.json({"pcap_file_path": str(pcap_file_path)})
|
||||
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to stop a packet capture",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -308,17 +307,29 @@ class DockerHandler:
|
||||
204: "Capture stopped",
|
||||
400: "Invalid request",
|
||||
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):
|
||||
|
||||
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():
|
||||
raise HTTPConflict(text="Cannot capture traffic on a non started VM")
|
||||
if not container.is_running():
|
||||
raise HTTPConflict(text="Cannot capture traffic on a non started Docker container")
|
||||
|
||||
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)
|
||||
|
||||
@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 asyncio
|
||||
from ....web.route import Route
|
||||
from ....schemas.dynamips_device import DEVICE_CREATE_SCHEMA
|
||||
from ....schemas.dynamips_device import DEVICE_UPDATE_SCHEMA
|
||||
from ....schemas.dynamips_device import DEVICE_OBJECT_SCHEMA
|
||||
from ....schemas.dynamips_device import DEVICE_NIO_SCHEMA
|
||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
||||
from ....compute.dynamips import Dynamips
|
||||
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
|
||||
from gns3server.compute.dynamips import Dynamips
|
||||
|
||||
from gns3server.schemas.dynamips_device import (
|
||||
DEVICE_CREATE_SCHEMA,
|
||||
DEVICE_UPDATE_SCHEMA,
|
||||
DEVICE_OBJECT_SCHEMA,
|
||||
DEVICE_NIO_SCHEMA
|
||||
)
|
||||
|
||||
|
||||
class DynamipsDeviceHandler:
|
||||
@@ -32,11 +36,10 @@ class DynamipsDeviceHandler:
|
||||
API entry points for Dynamips devices.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/devices",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
@@ -57,12 +60,11 @@ class DynamipsDeviceHandler:
|
||||
response.set_status(201)
|
||||
response.json(device)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/dynamips/devices/{device_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"device_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"device_id": "Device UUID"
|
||||
},
|
||||
status_codes={
|
||||
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"])
|
||||
response.json(device)
|
||||
|
||||
@classmethod
|
||||
@Route.put(
|
||||
r"/projects/{project_id}/dynamips/devices/{device_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"device_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"device_id": "Device UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance updated",
|
||||
@@ -107,12 +108,11 @@ class DynamipsDeviceHandler:
|
||||
|
||||
response.json(device)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/dynamips/devices/{device_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"device_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"device_id": "Device UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance deleted",
|
||||
@@ -129,8 +129,8 @@ class DynamipsDeviceHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"device_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"device_id": "Device UUID",
|
||||
"port_number": "Port on the device"
|
||||
},
|
||||
status_codes={
|
||||
@@ -162,12 +162,11 @@ class DynamipsDeviceHandler:
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"device_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"device_id": "Device UUID",
|
||||
"port_number": "Port on the device"
|
||||
},
|
||||
status_codes={
|
||||
@@ -188,8 +187,8 @@ class DynamipsDeviceHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/start_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"device_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"device_id": "Device UUID",
|
||||
"port_number": "Port on the device"
|
||||
},
|
||||
status_codes={
|
||||
@@ -211,8 +210,8 @@ class DynamipsDeviceHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/devices/{device_id}/ports/{port_number:\d+}/stop_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"device_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"device_id": "Device UUID",
|
||||
"port_number": "Port on the device"
|
||||
},
|
||||
status_codes={
|
||||
|
||||
@@ -19,17 +19,23 @@ import os
|
||||
import sys
|
||||
import base64
|
||||
|
||||
from ....web.route import Route
|
||||
from ....schemas.nio import NIO_SCHEMA
|
||||
from ....schemas.dynamips_vm import VM_CREATE_SCHEMA
|
||||
from ....schemas.dynamips_vm import VM_UPDATE_SCHEMA
|
||||
from ....schemas.dynamips_vm import VM_OBJECT_SCHEMA
|
||||
from ....schemas.dynamips_vm import VM_CONFIGS_SCHEMA
|
||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
||||
from ....schemas.node import NODE_LIST_IMAGES_SCHEMA
|
||||
from ....compute.dynamips import Dynamips
|
||||
from ....compute.dynamips.dynamips_error import DynamipsError
|
||||
from ....compute.project_manager import ProjectManager
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.schemas.nio import NIO_SCHEMA
|
||||
from gns3server.compute.dynamips import Dynamips
|
||||
from gns3server.compute.dynamips.dynamips_error import DynamipsError
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
|
||||
from gns3server.schemas.node import (
|
||||
NODE_CAPTURE_SCHEMA,
|
||||
NODE_LIST_IMAGES_SCHEMA,
|
||||
)
|
||||
|
||||
from gns3server.schemas.dynamips_vm import (
|
||||
VM_CREATE_SCHEMA,
|
||||
VM_UPDATE_SCHEMA,
|
||||
VM_OBJECT_SCHEMA,
|
||||
VM_CONFIGS_SCHEMA
|
||||
)
|
||||
|
||||
DEFAULT_CHASSIS = {
|
||||
"c1700": "1720",
|
||||
@@ -44,11 +50,10 @@ class DynamipsVMHandler:
|
||||
API entry points for Dynamips VMs.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
@@ -66,24 +71,23 @@ class DynamipsVMHandler:
|
||||
if platform in DEFAULT_CHASSIS:
|
||||
default_chassis = DEFAULT_CHASSIS[platform]
|
||||
vm = yield from dynamips_manager.create_node(request.json.pop("name"),
|
||||
request.match_info["project_id"],
|
||||
request.json.get("node_id"),
|
||||
request.json.get("dynamips_id"),
|
||||
platform,
|
||||
console=request.json.get("console"),
|
||||
aux=request.json.get("aux"),
|
||||
chassis=request.json.pop("chassis", default_chassis))
|
||||
request.match_info["project_id"],
|
||||
request.json.get("node_id"),
|
||||
request.json.get("dynamips_id"),
|
||||
platform,
|
||||
console=request.json.get("console"),
|
||||
aux=request.json.get("aux"),
|
||||
chassis=request.json.pop("chassis", default_chassis))
|
||||
|
||||
yield from dynamips_manager.update_vm_settings(vm, request.json)
|
||||
response.set_status(201)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
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"])
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.put(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance updated",
|
||||
@@ -121,12 +124,11 @@ class DynamipsVMHandler:
|
||||
yield from dynamips_manager.update_vm_settings(vm, request.json)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance deleted",
|
||||
@@ -138,16 +140,14 @@ class DynamipsVMHandler:
|
||||
|
||||
# check the project_id exists
|
||||
ProjectManager.instance().get_project(request.match_info["project_id"])
|
||||
|
||||
yield from Dynamips.instance().delete_node(request.match_info["node_id"])
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/start",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance started",
|
||||
@@ -166,12 +166,11 @@ class DynamipsVMHandler:
|
||||
yield from vm.start()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/stop",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance stopped",
|
||||
@@ -186,12 +185,11 @@ class DynamipsVMHandler:
|
||||
yield from vm.stop()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/suspend",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance suspended",
|
||||
@@ -206,12 +204,11 @@ class DynamipsVMHandler:
|
||||
yield from vm.suspend()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/resume",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance resumed",
|
||||
@@ -226,12 +223,11 @@ class DynamipsVMHandler:
|
||||
yield from vm.resume()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/reload",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance reloaded",
|
||||
@@ -249,8 +245,8 @@ class DynamipsVMHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter where the nio should be added",
|
||||
"port_number": "Port on the adapter"
|
||||
},
|
||||
@@ -273,12 +269,11 @@ class DynamipsVMHandler:
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter from where the nio should be removed",
|
||||
"port_number": "Port on the adapter"
|
||||
},
|
||||
@@ -301,8 +296,8 @@ class DynamipsVMHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to start a packet capture",
|
||||
"port_number": "Port on the adapter"
|
||||
},
|
||||
@@ -334,8 +329,8 @@ class DynamipsVMHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to stop a packet capture",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -356,6 +351,10 @@ class DynamipsVMHandler:
|
||||
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/configs",
|
||||
parameters={
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "Configs retrieved",
|
||||
400: "Invalid request",
|
||||
@@ -375,7 +374,7 @@ class DynamipsVMHandler:
|
||||
startup_config_content = base64.b64decode(startup_config_base64).decode("utf-8", errors='replace')
|
||||
result["startup_config_content"] = startup_config_content
|
||||
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
|
||||
if 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')
|
||||
result["private_config_content"] = private_config_content
|
||||
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
|
||||
if vm.private_config:
|
||||
private_config_path = os.path.join(module_workdir, vm.private_config)
|
||||
@@ -410,6 +409,10 @@ class DynamipsVMHandler:
|
||||
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/configs/save",
|
||||
parameters={
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "Configs saved",
|
||||
400: "Invalid request",
|
||||
@@ -425,6 +428,10 @@ class DynamipsVMHandler:
|
||||
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/idlepc_proposals",
|
||||
parameters={
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "Idle-PCs retrieved",
|
||||
400: "Invalid request",
|
||||
@@ -442,6 +449,10 @@ class DynamipsVMHandler:
|
||||
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/auto_idlepc",
|
||||
parameters={
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "Best Idle-pc value found",
|
||||
400: "Invalid request",
|
||||
@@ -457,28 +468,31 @@ class DynamipsVMHandler:
|
||||
response.json({"idlepc": idlepc})
|
||||
|
||||
@Route.get(
|
||||
r"/dynamips/nodes",
|
||||
r"/dynamips/images",
|
||||
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)
|
||||
def list_vms(request, response):
|
||||
def list_images(request, response):
|
||||
|
||||
dynamips_manager = Dynamips.instance()
|
||||
vms = yield from dynamips_manager.list_images()
|
||||
images = yield from dynamips_manager.list_images()
|
||||
response.set_status(200)
|
||||
response.json(vms)
|
||||
response.json(images)
|
||||
|
||||
@Route.post(
|
||||
r"/dynamips/nodes/{path}",
|
||||
r"/dynamips/images/{filename:.+}",
|
||||
parameters={
|
||||
"filename": "Image filename"
|
||||
},
|
||||
status_codes={
|
||||
204: "Image uploaded",
|
||||
204: "Upload a Dynamips IOS image",
|
||||
},
|
||||
raw=True,
|
||||
description="Upload Dynamips image")
|
||||
description="Upload a Dynamips IOS image")
|
||||
def upload_image(request, response):
|
||||
|
||||
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)
|
||||
@@ -18,16 +18,22 @@
|
||||
import os
|
||||
from aiohttp.web import HTTPConflict
|
||||
|
||||
from ....web.route import Route
|
||||
from ....schemas.nio import NIO_SCHEMA
|
||||
from ....schemas.iou import IOU_CREATE_SCHEMA
|
||||
from ....schemas.iou import IOU_START_SCHEMA
|
||||
from ....schemas.iou import IOU_UPDATE_SCHEMA
|
||||
from ....schemas.iou import IOU_OBJECT_SCHEMA
|
||||
from ....schemas.iou import IOU_CONFIGS_SCHEMA
|
||||
from ....schemas.node import NODE_LIST_IMAGES_SCHEMA
|
||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
||||
from ....compute.iou import IOU
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.schemas.nio import NIO_SCHEMA
|
||||
from gns3server.compute.iou import IOU
|
||||
|
||||
from gns3server.schemas.node import (
|
||||
NODE_CAPTURE_SCHEMA,
|
||||
NODE_LIST_IMAGES_SCHEMA,
|
||||
)
|
||||
|
||||
from gns3server.schemas.iou import (
|
||||
IOU_CREATE_SCHEMA,
|
||||
IOU_START_SCHEMA,
|
||||
IOU_UPDATE_SCHEMA,
|
||||
IOU_OBJECT_SCHEMA,
|
||||
IOU_CONFIGS_SCHEMA,
|
||||
)
|
||||
|
||||
|
||||
class IOUHandler:
|
||||
@@ -36,11 +42,10 @@ class IOUHandler:
|
||||
API entry points for IOU.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/iou/nodes",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
@@ -72,19 +77,18 @@ class IOUHandler:
|
||||
response.set_status(201)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Success",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Get a IOU instance",
|
||||
description="Get an IOU instance",
|
||||
output=IOU_OBJECT_SCHEMA)
|
||||
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"])
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.put(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance updated",
|
||||
@@ -105,7 +108,7 @@ class IOUHandler:
|
||||
404: "Instance doesn't exist",
|
||||
409: "Conflict"
|
||||
},
|
||||
description="Update a IOU instance",
|
||||
description="Update an IOU instance",
|
||||
input=IOU_UPDATE_SCHEMA,
|
||||
output=IOU_OBJECT_SCHEMA)
|
||||
def update(request, response):
|
||||
@@ -122,30 +125,28 @@ class IOUHandler:
|
||||
vm.private_config = request.json.get("private_config_content")
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance deleted",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Delete a IOU instance")
|
||||
description="Delete an IOU instance")
|
||||
def delete(request, response):
|
||||
|
||||
yield from IOU.instance().delete_node(request.match_info["node_id"])
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}/start",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance started",
|
||||
@@ -154,7 +155,7 @@ class IOUHandler:
|
||||
},
|
||||
input=IOU_START_SCHEMA,
|
||||
output=IOU_OBJECT_SCHEMA,
|
||||
description="Start a IOU instance")
|
||||
description="Start an IOU instance")
|
||||
def start(request, response):
|
||||
|
||||
iou_manager = IOU.instance()
|
||||
@@ -167,19 +168,18 @@ class IOUHandler:
|
||||
yield from vm.start()
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}/stop",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance stopped",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Stop a IOU instance")
|
||||
description="Stop an IOU instance")
|
||||
def stop(request, response):
|
||||
|
||||
iou_manager = IOU.instance()
|
||||
@@ -187,19 +187,18 @@ class IOUHandler:
|
||||
yield from vm.stop()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}/reload",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance reloaded",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Reload a IOU instance")
|
||||
description="Reload an IOU instance")
|
||||
def reload(request, response):
|
||||
|
||||
iou_manager = IOU.instance()
|
||||
@@ -210,8 +209,8 @@ class IOUHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Network adapter where the nio is located",
|
||||
"port_number": "Port where the nio should be added"
|
||||
},
|
||||
@@ -235,12 +234,11 @@ class IOUHandler:
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Network adapter where the nio is located",
|
||||
"port_number": "Port from where the nio should be removed"
|
||||
},
|
||||
@@ -260,8 +258,8 @@ class IOUHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to start a packet capture",
|
||||
"port_number": "Port on the adapter"
|
||||
},
|
||||
@@ -271,7 +269,7 @@ class IOUHandler:
|
||||
404: "Instance doesn't exist",
|
||||
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)
|
||||
def start_capture(request, response):
|
||||
|
||||
@@ -288,8 +286,8 @@ class IOUHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to stop a packet capture",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -299,7 +297,7 @@ class IOUHandler:
|
||||
404: "Instance doesn't exist",
|
||||
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):
|
||||
|
||||
iou_manager = IOU.instance()
|
||||
@@ -315,6 +313,10 @@ class IOUHandler:
|
||||
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}/configs",
|
||||
parameters={
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Configs retrieved",
|
||||
400: "Invalid request",
|
||||
@@ -352,6 +354,10 @@ class IOUHandler:
|
||||
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/iou/nodes/{node_id}/configs/save",
|
||||
parameters={
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Configs saved",
|
||||
400: "Invalid request",
|
||||
@@ -366,28 +372,31 @@ class IOUHandler:
|
||||
response.set_status(200)
|
||||
|
||||
@Route.get(
|
||||
r"/iou/nodes",
|
||||
r"/iou/images",
|
||||
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)
|
||||
def list_iou_nodes(request, response):
|
||||
def list_iou_images(request, response):
|
||||
|
||||
iou_manager = IOU.instance()
|
||||
iou_nodes = yield from iou_manager.list_images()
|
||||
images = yield from iou_manager.list_images()
|
||||
response.set_status(200)
|
||||
response.json(iou_nodes)
|
||||
response.json(images)
|
||||
|
||||
@Route.post(
|
||||
r"/iou/nodes/{path}",
|
||||
r"/iou/images/{filename:.+}",
|
||||
parameters={
|
||||
"filename": "Image filename"
|
||||
},
|
||||
status_codes={
|
||||
204: "Image uploaded",
|
||||
},
|
||||
raw=True,
|
||||
description="Upload IOU image.")
|
||||
description="Upload an IOU image")
|
||||
def upload_image(request, response):
|
||||
|
||||
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)
|
||||
@@ -15,19 +15,18 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from ....web.route import Route
|
||||
from ....compute.port_manager import PortManager
|
||||
from ....compute.project_manager import ProjectManager
|
||||
from ....utils.interfaces import interfaces
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.compute.port_manager import PortManager
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
from gns3server.utils.interfaces import interfaces
|
||||
|
||||
|
||||
class NetworkHandler:
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/ports/udp",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
201: "UDP port allocated",
|
||||
@@ -43,7 +42,6 @@ class NetworkHandler:
|
||||
response.set_status(201)
|
||||
response.json({"udp_port": udp_port})
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/interfaces",
|
||||
description="List all the network interfaces available on the server")
|
||||
|
||||
@@ -17,17 +17,16 @@
|
||||
|
||||
import asyncio
|
||||
|
||||
from ....web.route import Route
|
||||
from ....compute.notification_manager import NotificationManager
|
||||
from aiohttp.web import WebSocketResponse
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.compute.notification_manager import NotificationManager
|
||||
|
||||
|
||||
class NotificationHandler:
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/notifications/ws",
|
||||
description="Send notifications about what happend using websockets")
|
||||
description="Send notifications using Websockets")
|
||||
def notifications(request, response):
|
||||
notifications = NotificationManager.instance()
|
||||
ws = WebSocketResponse()
|
||||
@@ -36,8 +35,8 @@ class NotificationHandler:
|
||||
with notifications.queue() as queue:
|
||||
while True:
|
||||
try:
|
||||
notif = yield from queue.get_json(5)
|
||||
except asyncio.futures.CancelledError as e:
|
||||
notification = yield from queue.get_json(5)
|
||||
except asyncio.futures.CancelledError:
|
||||
break
|
||||
ws.send_str(notif)
|
||||
ws.send_str(notification)
|
||||
return ws
|
||||
@@ -22,10 +22,17 @@ import os
|
||||
import psutil
|
||||
import tempfile
|
||||
|
||||
from ....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 ....compute.project_manager import ProjectManager
|
||||
from ....compute import MODULES
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
from gns3server.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
|
||||
log = logging.getLogger()
|
||||
@@ -33,13 +40,12 @@ log = logging.getLogger()
|
||||
|
||||
class ProjectHandler:
|
||||
|
||||
# How many clients has subcribe to notifications
|
||||
# How many clients have subscribed to notifications
|
||||
_notifications_listening = {}
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects",
|
||||
description="List projects opened on the server",
|
||||
description="List all projects opened on the server",
|
||||
status_codes={
|
||||
200: "Project list",
|
||||
},
|
||||
@@ -51,13 +57,12 @@ class ProjectHandler:
|
||||
response.set_status(200)
|
||||
response.json(list(pm.projects))
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects",
|
||||
description="Create a new project on the server",
|
||||
status_codes={
|
||||
201: "Project created",
|
||||
403: "You are not allowed to modify this property",
|
||||
403: "Forbidden to create a project",
|
||||
409: "Project already created"
|
||||
},
|
||||
output=PROJECT_OBJECT_SCHEMA,
|
||||
@@ -74,12 +79,11 @@ class ProjectHandler:
|
||||
response.set_status(201)
|
||||
response.json(p)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}",
|
||||
description="Get project information",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "Success",
|
||||
@@ -92,16 +96,15 @@ class ProjectHandler:
|
||||
project = pm.get_project(request.match_info["project_id"])
|
||||
response.json(project)
|
||||
|
||||
@classmethod
|
||||
@Route.put(
|
||||
r"/projects/{project_id}",
|
||||
description="Update a project",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "The project has been updated",
|
||||
403: "You are not allowed to modify this property",
|
||||
200: "Project updated",
|
||||
403: "Forbidden to update this project",
|
||||
404: "The project doesn't exist"
|
||||
},
|
||||
output=PROJECT_OBJECT_SCHEMA,
|
||||
@@ -118,16 +121,15 @@ class ProjectHandler:
|
||||
for module in MODULES:
|
||||
yield from module.instance().project_moved(project)
|
||||
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)
|
||||
response.json(project)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/commit",
|
||||
description="Write changes on disk",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Changes have been written on disk",
|
||||
@@ -140,15 +142,14 @@ class ProjectHandler:
|
||||
yield from project.commit()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/close",
|
||||
description="Close a project",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "The project has been closed",
|
||||
204: "Project closed",
|
||||
404: "The project doesn't exist"
|
||||
})
|
||||
def close(request, response):
|
||||
@@ -160,15 +161,14 @@ class ProjectHandler:
|
||||
pm.remove_project(project.id)
|
||||
del ProjectHandler._notifications_listening[project.id]
|
||||
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)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}",
|
||||
description="Delete a project from disk",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Changes have been written on disk",
|
||||
@@ -182,12 +182,11 @@ class ProjectHandler:
|
||||
pm.remove_project(project.id)
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/notifications",
|
||||
description="Receive notifications about the projects",
|
||||
description="Receive notifications about the project",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "End of stream",
|
||||
@@ -201,7 +200,7 @@ class ProjectHandler:
|
||||
response.content_type = "application/json"
|
||||
response.set_status(200)
|
||||
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.start(request)
|
||||
@@ -226,30 +225,27 @@ class ProjectHandler:
|
||||
if project.id in ProjectHandler._notifications_listening:
|
||||
ProjectHandler._notifications_listening[project.id] -= 1
|
||||
|
||||
@classmethod
|
||||
def _getPingMessage(cls):
|
||||
"""
|
||||
The ping message is regulary send to the client to
|
||||
keep the connection open. We send with it some informations
|
||||
about server load.
|
||||
Ping messages are regularly sent to the client to
|
||||
keep the connection open. We send with it some information about server load.
|
||||
|
||||
:returns: hash
|
||||
"""
|
||||
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["memory_usage_percent"] = psutil.virtual_memory().percent
|
||||
return {"action": "ping", "event": stats}
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/files",
|
||||
description="List files of a project",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "Return list of files",
|
||||
200: "Return a list of files",
|
||||
404: "The project doesn't exist"
|
||||
},
|
||||
output=PROJECT_FILE_LIST_SCHEMA)
|
||||
@@ -261,15 +257,14 @@ class ProjectHandler:
|
||||
response.json(files)
|
||||
response.set_status(200)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/files/{path:.+}",
|
||||
description="Get a file of a project",
|
||||
description="Get a file from a project",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "Return the file",
|
||||
200: "File returned",
|
||||
403: "Permission denied",
|
||||
404: "The file doesn't exist"
|
||||
})
|
||||
@@ -280,7 +275,7 @@ class ProjectHandler:
|
||||
path = request.match_info["path"]
|
||||
path = os.path.normpath(path)
|
||||
|
||||
# Raise error if user try to escape
|
||||
# Raise an error if user try to escape
|
||||
if path[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden
|
||||
path = os.path.join(project.path, path)
|
||||
@@ -288,7 +283,7 @@ class ProjectHandler:
|
||||
response.content_type = "application/octet-stream"
|
||||
response.set_status(200)
|
||||
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
|
||||
|
||||
try:
|
||||
@@ -305,15 +300,14 @@ class ProjectHandler:
|
||||
except PermissionError:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/stream/{path:.+}",
|
||||
description="Stream a file from a project",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "Return the file",
|
||||
200: "File returned",
|
||||
403: "Permission denied",
|
||||
404: "The file doesn't exist"
|
||||
})
|
||||
@@ -324,7 +318,7 @@ class ProjectHandler:
|
||||
path = request.match_info["path"]
|
||||
path = os.path.normpath(path)
|
||||
|
||||
# Raise error if user try to escape
|
||||
# Raise an error if user try to escape
|
||||
if path[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden
|
||||
path = os.path.join(project.path, path)
|
||||
@@ -332,7 +326,7 @@ class ProjectHandler:
|
||||
response.content_type = "application/octet-stream"
|
||||
response.set_status(200)
|
||||
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
|
||||
|
||||
try:
|
||||
@@ -349,16 +343,15 @@ class ProjectHandler:
|
||||
except PermissionError:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/files/{path:.+}",
|
||||
description="Get a file of a project",
|
||||
description="Write a file to a project",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
raw=True,
|
||||
status_codes={
|
||||
200: "Return the file",
|
||||
200: "File returned",
|
||||
403: "Permission denied",
|
||||
404: "The path doesn't exist"
|
||||
})
|
||||
@@ -389,16 +382,15 @@ class ProjectHandler:
|
||||
except PermissionError:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/export",
|
||||
description="Export a project as a portable archive",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
raw=True,
|
||||
status_codes={
|
||||
200: "Return the file",
|
||||
200: "File returned",
|
||||
404: "The project doesn't exist"
|
||||
})
|
||||
def export_project(request, response):
|
||||
@@ -408,7 +400,7 @@ class ProjectHandler:
|
||||
response.content_type = 'application/gns3project'
|
||||
response.headers['CONTENT-DISPOSITION'] = 'attachment; filename="{}.gns3project"'.format(project.name)
|
||||
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.start(request)
|
||||
|
||||
@@ -418,18 +410,17 @@ class ProjectHandler:
|
||||
|
||||
yield from response.write_eof()
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/import",
|
||||
description="Import a project from a portable archive",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
raw=True,
|
||||
output=PROJECT_OBJECT_SCHEMA,
|
||||
status_codes={
|
||||
200: "Project imported",
|
||||
403: "You are not allowed to modify this property"
|
||||
403: "Forbidden to import project"
|
||||
})
|
||||
def import_project(request, response):
|
||||
|
||||
@@ -437,11 +428,9 @@ class ProjectHandler:
|
||||
project_id = request.match_info["project_id"]
|
||||
project = pm.create_project(project_id=project_id)
|
||||
|
||||
# We write the content to a temporary location
|
||||
# and after extract all. It could be more optimal to stream
|
||||
# this but it's not implemented in Python.
|
||||
#
|
||||
# Spooled mean the file is temporary keep in ram until max_size
|
||||
# We write the content to a temporary location and after we extract it all.
|
||||
# It could be more optimal to stream this but it is not implemented in Python.
|
||||
# Spooled means the file is temporary kept in memory until max_size is reached
|
||||
try:
|
||||
with tempfile.SpooledTemporaryFile(max_size=10000) as temp:
|
||||
while True:
|
||||
|
||||
@@ -19,19 +19,23 @@ import sys
|
||||
import os.path
|
||||
|
||||
from aiohttp.web import HTTPConflict
|
||||
from ....web.route import Route
|
||||
from ....compute.project_manager import ProjectManager
|
||||
from ....schemas.nio import NIO_SCHEMA
|
||||
from ....schemas.qemu import QEMU_CREATE_SCHEMA
|
||||
from ....schemas.qemu import QEMU_UPDATE_SCHEMA
|
||||
from ....schemas.qemu import QEMU_OBJECT_SCHEMA
|
||||
from ....schemas.qemu import QEMU_BINARY_FILTER_SCHEMA
|
||||
from ....schemas.qemu import QEMU_BINARY_LIST_SCHEMA
|
||||
from ....schemas.qemu import QEMU_CAPABILITY_LIST_SCHEMA
|
||||
from ....schemas.qemu import QEMU_IMAGE_CREATE_SCHEMA
|
||||
from ....schemas.node import NODE_LIST_IMAGES_SCHEMA
|
||||
from ....compute.qemu import Qemu
|
||||
from ....config import Config
|
||||
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
from gns3server.schemas.nio import NIO_SCHEMA
|
||||
from gns3server.schemas.node import NODE_LIST_IMAGES_SCHEMA
|
||||
from gns3server.compute.qemu import Qemu
|
||||
from gns3server.config import Config
|
||||
|
||||
from gns3server.schemas.qemu import (
|
||||
QEMU_CREATE_SCHEMA,
|
||||
QEMU_UPDATE_SCHEMA,
|
||||
QEMU_OBJECT_SCHEMA,
|
||||
QEMU_BINARY_LIST_SCHEMA,
|
||||
QEMU_BINARY_FILTER_SCHEMA,
|
||||
QEMU_CAPABILITY_LIST_SCHEMA,
|
||||
QEMU_IMAGE_CREATE_SCHEMA
|
||||
)
|
||||
|
||||
|
||||
class QEMUHandler:
|
||||
@@ -40,11 +44,10 @@ class QEMUHandler:
|
||||
API entry points for QEMU.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/qemu/nodes",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
@@ -73,12 +76,11 @@ class QEMUHandler:
|
||||
response.set_status(201)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
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"])
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.put(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance updated",
|
||||
@@ -120,12 +121,11 @@ class QEMUHandler:
|
||||
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance deleted",
|
||||
@@ -138,12 +138,11 @@ class QEMUHandler:
|
||||
yield from Qemu.instance().delete_node(request.match_info["node_id"])
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}/start",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance started",
|
||||
@@ -156,20 +155,18 @@ class QEMUHandler:
|
||||
|
||||
qemu_manager = Qemu.instance()
|
||||
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) \
|
||||
and "-no-kvm" not in vm.options:
|
||||
if sys.platform.startswith("linux") and qemu_manager.config.get_section_config("Qemu").getboolean("enable_kvm", True) and "-no-kvm" not in vm.options:
|
||||
pm = ProjectManager.instance()
|
||||
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")
|
||||
yield from vm.start()
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}/stop",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"vm_node": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance stopped",
|
||||
@@ -184,12 +181,11 @@ class QEMUHandler:
|
||||
yield from vm.stop()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}/reload",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance reloaded",
|
||||
@@ -204,12 +200,11 @@ class QEMUHandler:
|
||||
yield from vm.reload()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}/suspend",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance suspended",
|
||||
@@ -224,12 +219,11 @@ class QEMUHandler:
|
||||
yield from vm.suspend()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}/resume",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance resumed",
|
||||
@@ -247,8 +241,8 @@ class QEMUHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Network adapter where the nio is located",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -272,12 +266,11 @@ class QEMUHandler:
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Network adapter where the nio is located",
|
||||
"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"]))
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/qemu/binaries",
|
||||
status_codes={
|
||||
@@ -310,7 +302,6 @@ class QEMUHandler:
|
||||
binaries = yield from Qemu.binary_list(request.json.get("archs", None))
|
||||
response.json(binaries)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/qemu/img-binaries",
|
||||
status_codes={
|
||||
@@ -340,7 +331,6 @@ class QEMUHandler:
|
||||
capabilities["kvm"] = kvms
|
||||
response.json(capabilities)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/qemu/img",
|
||||
status_codes={
|
||||
@@ -363,28 +353,31 @@ class QEMUHandler:
|
||||
response.set_status(201)
|
||||
|
||||
@Route.get(
|
||||
r"/qemu/nodes",
|
||||
r"/qemu/images",
|
||||
status_codes={
|
||||
200: "List of Qemu images retrieved",
|
||||
200: "List of Qemu images",
|
||||
},
|
||||
description="Retrieve the list of Qemu images",
|
||||
output=NODE_LIST_IMAGES_SCHEMA)
|
||||
def list_vm_nodes(request, response):
|
||||
def list_qemu_images(request, response):
|
||||
|
||||
qemu_manager = Qemu.instance()
|
||||
vm_nodes = yield from qemu_manager.list_images()
|
||||
images = yield from qemu_manager.list_images()
|
||||
response.set_status(200)
|
||||
response.json(vm_nodes)
|
||||
response.json(images)
|
||||
|
||||
@Route.post(
|
||||
r"/qemu/nodes/{path:.+}",
|
||||
r"/qemu/images/{filename:.+}",
|
||||
parameters={
|
||||
"filename": "Image filename"
|
||||
},
|
||||
status_codes={
|
||||
204: "Image uploaded",
|
||||
},
|
||||
raw=True,
|
||||
description="Upload Qemu image.")
|
||||
description="Upload Qemu image")
|
||||
def upload_image(request, response):
|
||||
|
||||
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)
|
||||
@@ -15,16 +15,15 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from ....web.route import Route
|
||||
from ....config import Config
|
||||
from ....schemas.version import VERSION_SCHEMA
|
||||
from ....version import __version__
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.config import Config
|
||||
from gns3server.schemas.version import VERSION_SCHEMA
|
||||
from gns3server.version import __version__
|
||||
from aiohttp.web import HTTPConflict
|
||||
|
||||
|
||||
class VersionHandler:
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/version",
|
||||
description="Retrieve the server version number",
|
||||
@@ -35,7 +34,6 @@ class VersionHandler:
|
||||
local_server = config.get_section_config("Server").getboolean("local", False)
|
||||
response.json({"version": __version__, "local": local_server})
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/version",
|
||||
description="Check if version is the same as the server",
|
||||
|
||||
@@ -18,15 +18,17 @@
|
||||
import os
|
||||
|
||||
from aiohttp.web import HTTPConflict
|
||||
from ....web.route import Route
|
||||
from ....schemas.nio import NIO_SCHEMA
|
||||
from ....schemas.virtualbox import VBOX_CREATE_SCHEMA
|
||||
from ....schemas.virtualbox import VBOX_UPDATE_SCHEMA
|
||||
from ....schemas.virtualbox import VBOX_OBJECT_SCHEMA
|
||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
||||
from ....compute.virtualbox import VirtualBox
|
||||
from ....compute.project_manager import ProjectManager
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.schemas.nio import NIO_SCHEMA
|
||||
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
|
||||
from gns3server.compute.virtualbox import VirtualBox
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
|
||||
from gns3server.schemas.virtualbox import (
|
||||
VBOX_CREATE_SCHEMA,
|
||||
VBOX_UPDATE_SCHEMA,
|
||||
VBOX_OBJECT_SCHEMA
|
||||
)
|
||||
|
||||
class VirtualBoxHandler:
|
||||
|
||||
@@ -34,24 +36,10 @@ class VirtualBoxHandler:
|
||||
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(
|
||||
r"/projects/{project_id}/virtualbox/nodes",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
@@ -88,12 +76,11 @@ class VirtualBoxHandler:
|
||||
response.set_status(201)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
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"])
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.put(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance updated",
|
||||
@@ -153,12 +139,11 @@ class VirtualBoxHandler:
|
||||
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance deleted",
|
||||
@@ -170,16 +155,14 @@ class VirtualBoxHandler:
|
||||
|
||||
# check the project_id exists
|
||||
ProjectManager.instance().get_project(request.match_info["project_id"])
|
||||
|
||||
yield from VirtualBox.instance().delete_node(request.match_info["node_id"])
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/start",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance started",
|
||||
@@ -198,12 +181,11 @@ class VirtualBoxHandler:
|
||||
yield from vm.start()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/stop",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance stopped",
|
||||
@@ -218,12 +200,11 @@ class VirtualBoxHandler:
|
||||
yield from vm.stop()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/suspend",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance suspended",
|
||||
@@ -238,12 +219,11 @@ class VirtualBoxHandler:
|
||||
yield from vm.suspend()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/resume",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance resumed",
|
||||
@@ -258,12 +238,11 @@ class VirtualBoxHandler:
|
||||
yield from vm.resume()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/reload",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance reloaded",
|
||||
@@ -281,8 +260,8 @@ class VirtualBoxHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter where the nio should be added",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -306,12 +285,11 @@ class VirtualBoxHandler:
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter from where the nio should be removed",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -331,8 +309,8 @@ class VirtualBoxHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to start a packet capture",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -355,8 +333,8 @@ class VirtualBoxHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to stop a packet capture",
|
||||
"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.stop_capture(int(request.match_info["adapter_number"]))
|
||||
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
|
||||
|
||||
from aiohttp.web import HTTPConflict
|
||||
from ....web.route import Route
|
||||
from ....schemas.vmware import VMWARE_CREATE_SCHEMA
|
||||
from ....schemas.vmware import VMWARE_UPDATE_SCHEMA
|
||||
from ....schemas.vmware import VMWARE_OBJECT_SCHEMA
|
||||
from ....schemas.node import NODE_CAPTURE_SCHEMA
|
||||
from ....schemas.nio import NIO_SCHEMA
|
||||
from ....compute.vmware import VMware
|
||||
from ....compute.project_manager import ProjectManager
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
|
||||
from gns3server.schemas.nio import NIO_SCHEMA
|
||||
from gns3server.compute.vmware import VMware
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
|
||||
from gns3server.schemas.vmware import (
|
||||
VMWARE_CREATE_SCHEMA,
|
||||
VMWARE_UPDATE_SCHEMA,
|
||||
VMWARE_OBJECT_SCHEMA
|
||||
)
|
||||
|
||||
|
||||
class VMwareHandler:
|
||||
@@ -34,24 +37,10 @@ class VMwareHandler:
|
||||
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(
|
||||
r"/projects/{project_id}/vmware/nodes",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
@@ -79,12 +68,11 @@ class VMwareHandler:
|
||||
response.set_status(201)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
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"])
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.put(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance updated",
|
||||
@@ -126,12 +113,11 @@ class VMwareHandler:
|
||||
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance deleted",
|
||||
@@ -146,12 +132,11 @@ class VMwareHandler:
|
||||
yield from VMware.instance().delete_node(request.match_info["node_id"])
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/start",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance started",
|
||||
@@ -170,12 +155,11 @@ class VMwareHandler:
|
||||
yield from vm.start()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/stop",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance stopped",
|
||||
@@ -190,12 +174,11 @@ class VMwareHandler:
|
||||
yield from vm.stop()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/suspend",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance suspended",
|
||||
@@ -210,12 +193,11 @@ class VMwareHandler:
|
||||
yield from vm.suspend()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/resume",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance resumed",
|
||||
@@ -230,12 +212,11 @@ class VMwareHandler:
|
||||
yield from vm.resume()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/reload",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance reloaded",
|
||||
@@ -253,8 +234,8 @@ class VMwareHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter where the nio should be added",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -278,12 +259,11 @@ class VMwareHandler:
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter from where the nio should be removed",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -303,8 +283,8 @@ class VMwareHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to start a packet capture",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -327,8 +307,8 @@ class VMwareHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Adapter to stop a packet capture",
|
||||
"port_number": "Port on the adapter (always 0)"
|
||||
},
|
||||
@@ -346,12 +326,11 @@ class VMwareHandler:
|
||||
yield from vm.stop_capture(adapter_number)
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vmware/nodes/{node_id}/interfaces/vmnet",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
201: "VMnet interface allocated",
|
||||
@@ -366,3 +345,14 @@ class VMwareHandler:
|
||||
vm.vmnets.append(vmnet)
|
||||
response.set_status(201)
|
||||
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/>.
|
||||
|
||||
from aiohttp.web import HTTPConflict
|
||||
from ....web.route import Route
|
||||
from ....schemas.nio import NIO_SCHEMA
|
||||
from ....schemas.vpcs import VPCS_CREATE_SCHEMA
|
||||
from ....schemas.vpcs import VPCS_UPDATE_SCHEMA
|
||||
from ....schemas.vpcs import VPCS_OBJECT_SCHEMA
|
||||
from ....compute.vpcs import VPCS
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.schemas.nio import NIO_SCHEMA
|
||||
from gns3server.compute.vpcs import VPCS
|
||||
|
||||
from gns3server.schemas.vpcs import (
|
||||
VPCS_CREATE_SCHEMA,
|
||||
VPCS_UPDATE_SCHEMA,
|
||||
VPCS_OBJECT_SCHEMA
|
||||
)
|
||||
|
||||
|
||||
class VPCSHandler:
|
||||
@@ -30,11 +33,10 @@ class VPCSHandler:
|
||||
API entry points for VPCS.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vpcs/nodes",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
@@ -47,20 +49,19 @@ class VPCSHandler:
|
||||
def create(request, response):
|
||||
|
||||
vpcs = VPCS.instance()
|
||||
node = yield from vpcs.create_node(request.json["name"],
|
||||
request.match_info["project_id"],
|
||||
request.json.get("node_id"),
|
||||
console=request.json.get("console"),
|
||||
startup_script=request.json.get("startup_script"))
|
||||
vm = yield from vpcs.create_node(request.json["name"],
|
||||
request.match_info["project_id"],
|
||||
request.json.get("node_id"),
|
||||
console=request.json.get("console"),
|
||||
startup_script=request.json.get("startup_script"))
|
||||
response.set_status(201)
|
||||
response.json(node)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/vpcs/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
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"])
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.put(
|
||||
r"/projects/{project_id}/vpcs/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "Instance updated",
|
||||
@@ -100,12 +100,11 @@ class VPCSHandler:
|
||||
vm.startup_script = request.json.get("startup_script", vm.startup_script)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/vpcs/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance deleted",
|
||||
@@ -118,12 +117,11 @@ class VPCSHandler:
|
||||
yield from VPCS.instance().delete_node(request.match_info["node_id"])
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/start",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance started",
|
||||
@@ -139,12 +137,11 @@ class VPCSHandler:
|
||||
yield from vm.start()
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/stop",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance stopped",
|
||||
@@ -159,12 +156,11 @@ class VPCSHandler:
|
||||
yield from vm.stop()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/reload",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance reloaded",
|
||||
@@ -182,8 +178,8 @@ class VPCSHandler:
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Network adapter where the nio is located",
|
||||
"port_number": "Port where the nio should be added"
|
||||
},
|
||||
@@ -207,12 +203,11 @@ class VPCSHandler:
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the instance",
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID",
|
||||
"adapter_number": "Network adapter where the nio is located",
|
||||
"port_number": "Port from where the nio should be removed"
|
||||
},
|
||||
|
||||
@@ -18,27 +18,24 @@
|
||||
import asyncio
|
||||
from aiohttp.web import HTTPForbidden
|
||||
|
||||
from ....web.route import Route
|
||||
from ....config import Config
|
||||
from ....compute.project_manager import ProjectManager
|
||||
from ....schemas.compute import COMPUTE_CREATE_SCHEMA, COMPUTE_OBJECT_SCHEMA
|
||||
from ....controller import Controller
|
||||
from ....controller.compute import Compute
|
||||
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.config import Config
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
from gns3server.schemas.compute import COMPUTE_CREATE_SCHEMA, COMPUTE_OBJECT_SCHEMA
|
||||
from gns3server.controller import Controller
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ComputeHandler:
|
||||
"""API entry points for compute management."""
|
||||
"""API entry points for compute server management."""
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/computes",
|
||||
description="Register a compute",
|
||||
description="Register a compute server",
|
||||
status_codes={
|
||||
201: "Compute added"
|
||||
201: "Compute server added"
|
||||
},
|
||||
input=COMPUTE_CREATE_SCHEMA,
|
||||
output=COMPUTE_OBJECT_SCHEMA)
|
||||
@@ -48,31 +45,29 @@ class ComputeHandler:
|
||||
response.set_status(201)
|
||||
response.json(compute)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/computes",
|
||||
description="List compute nodes",
|
||||
description="List of compute server",
|
||||
status_codes={
|
||||
200: "Compute list"
|
||||
200: "Compute servers list returned"
|
||||
})
|
||||
def list(request, response):
|
||||
|
||||
controller = Controller.instance()
|
||||
response.json([c for c in controller.computes.values()])
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/computes/shutdown",
|
||||
description="Shutdown the local compute",
|
||||
description="Shutdown a local compute server",
|
||||
status_codes={
|
||||
201: "Compute is shutting down",
|
||||
403: "Compute shutdown refused"
|
||||
201: "Compute server is shutting down",
|
||||
403: "Compute server shutdown refused"
|
||||
})
|
||||
def shutdown(request, response):
|
||||
|
||||
config = Config.instance()
|
||||
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
|
||||
pm = ProjectManager.instance()
|
||||
@@ -97,12 +92,12 @@ class ComputeHandler:
|
||||
asyncio.async(server.shutdown_server())
|
||||
response.set_status(201)
|
||||
|
||||
@classmethod
|
||||
|
||||
@Route.get(
|
||||
r"/computes/{compute_id:.+}",
|
||||
description="Get a compute node informations",
|
||||
description="Get a compute server information",
|
||||
status_codes={
|
||||
200: "Compute list"
|
||||
200: "Compute server information returned"
|
||||
},
|
||||
output=COMPUTE_OBJECT_SCHEMA)
|
||||
def get(request, response):
|
||||
|
||||
@@ -17,9 +17,13 @@
|
||||
|
||||
import aiohttp
|
||||
|
||||
from ....web.route import Route
|
||||
from ....schemas.link import LINK_OBJECT_SCHEMA, LINK_CAPTURE_SCHEMA
|
||||
from ....controller import Controller
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.controller import Controller
|
||||
|
||||
from gns3server.schemas.link import (
|
||||
LINK_OBJECT_SCHEMA,
|
||||
LINK_CAPTURE_SCHEMA
|
||||
)
|
||||
|
||||
|
||||
class LinkHandler:
|
||||
@@ -27,11 +31,10 @@ class LinkHandler:
|
||||
API entry point for Link
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/links",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Link created",
|
||||
@@ -51,12 +54,11 @@ class LinkHandler:
|
||||
response.set_status(201)
|
||||
response.json(link)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/links/{link_id}/start_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"link_id": "UUID of the link"
|
||||
"project_id": "Project UUID",
|
||||
"link_id": "Link UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Capture started",
|
||||
@@ -64,7 +66,7 @@ class LinkHandler:
|
||||
},
|
||||
input=LINK_CAPTURE_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):
|
||||
|
||||
controller = Controller.instance()
|
||||
@@ -74,12 +76,11 @@ class LinkHandler:
|
||||
response.set_status(201)
|
||||
response.json(link)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/links/{link_id}/stop_capture",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"link_id": "UUID of the link"
|
||||
"project_id": "Project UUID",
|
||||
"link_id": "Link UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Capture stopped",
|
||||
@@ -95,12 +96,11 @@ class LinkHandler:
|
||||
response.set_status(201)
|
||||
response.json(link)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/links/{link_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"link_id": "UUID of the link"
|
||||
"project_id": "Project UUID",
|
||||
"link_id": "Link UUID"
|
||||
},
|
||||
status_codes={
|
||||
204: "Link deleted",
|
||||
@@ -116,16 +116,15 @@ class LinkHandler:
|
||||
response.set_status(204)
|
||||
response.json(link)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/links/{link_id}/pcap",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"link_id": "UUID of the link"
|
||||
"project_id": "Project UUID",
|
||||
"link_id": "Link UUID"
|
||||
},
|
||||
description="Get the pcap from the capture",
|
||||
description="Steam the pcap capture file",
|
||||
status_codes={
|
||||
200: "Return the file",
|
||||
200: "File returned",
|
||||
403: "Permission denied",
|
||||
404: "The file doesn't exist"
|
||||
})
|
||||
@@ -145,7 +144,7 @@ class LinkHandler:
|
||||
response.content_type = "application/vnd.tcpdump.pcap"
|
||||
response.set_status(200)
|
||||
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.start(request)
|
||||
|
||||
|
||||
@@ -15,9 +15,13 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from ....web.route import Route
|
||||
from ....schemas.node import NODE_OBJECT_SCHEMA, NODE_UPDATE_SCHEMA
|
||||
from ....controller import Controller
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.controller import Controller
|
||||
|
||||
from gns3server.schemas.node import (
|
||||
NODE_OBJECT_SCHEMA,
|
||||
NODE_UPDATE_SCHEMA
|
||||
)
|
||||
|
||||
|
||||
class NodeHandler:
|
||||
@@ -25,11 +29,10 @@ class NodeHandler:
|
||||
API entry point for node
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/nodes",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
@@ -47,28 +50,27 @@ class NodeHandler:
|
||||
response.set_status(201)
|
||||
response.json(node)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/nodes",
|
||||
parameters={
|
||||
"project_id": "UUID for the project"
|
||||
"project_id": "Project UUID"
|
||||
},
|
||||
status_codes={
|
||||
200: "List of nodes",
|
||||
200: "List of nodes returned",
|
||||
},
|
||||
description="List nodes of a project")
|
||||
def list_nodes(request, response):
|
||||
|
||||
controller = Controller.instance()
|
||||
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(
|
||||
r"/projects/{project_id}/nodes/{node_id}",
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
400: "Invalid request"
|
||||
200: "Instance updated",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Update a node instance",
|
||||
input=NODE_UPDATE_SCHEMA,
|
||||
@@ -77,25 +79,25 @@ class NodeHandler:
|
||||
project = Controller.instance().get_project(request.match_info["project_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_type", None)
|
||||
request.json.pop("compute_id", None)
|
||||
|
||||
yield from node.update(**request.json)
|
||||
response.set_status(201)
|
||||
response.set_status(200)
|
||||
response.json(node)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/nodes/{node_id}/start",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the node"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
400: "Invalid request"
|
||||
204: "Instance started",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Start a node instance",
|
||||
output=NODE_OBJECT_SCHEMA)
|
||||
@@ -104,61 +106,58 @@ class NodeHandler:
|
||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||
node = project.get_node(request.match_info["node_id"])
|
||||
yield from node.start()
|
||||
response.set_status(201)
|
||||
response.json(node)
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/nodes/{node_id}/stop",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the node"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
400: "Invalid request"
|
||||
204: "Instance stopped",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Start a node instance",
|
||||
description="Stop a node instance",
|
||||
output=NODE_OBJECT_SCHEMA)
|
||||
def stop(request, response):
|
||||
|
||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||
node = project.get_node(request.match_info["node_id"])
|
||||
yield from node.stop()
|
||||
response.set_status(201)
|
||||
response.json(node)
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/nodes/{node_id}/suspend",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the node"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
400: "Invalid request"
|
||||
204: "Instance suspended",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Start a node instance",
|
||||
description="Suspend a node instance",
|
||||
output=NODE_OBJECT_SCHEMA)
|
||||
def suspend(request, response):
|
||||
|
||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||
node = project.get_node(request.match_info["node_id"])
|
||||
yield from node.suspend()
|
||||
response.set_status(201)
|
||||
response.json(node)
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/nodes/{node_id}/reload",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the node"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance created",
|
||||
400: "Invalid request"
|
||||
204: "Instance reloaded",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Reload a node instance",
|
||||
output=NODE_OBJECT_SCHEMA)
|
||||
@@ -167,23 +166,22 @@ class NodeHandler:
|
||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||
node = project.get_node(request.match_info["node_id"])
|
||||
yield from node.reload()
|
||||
response.set_status(201)
|
||||
response.json(node)
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}/nodes/{node_id}",
|
||||
parameters={
|
||||
"project_id": "UUID for the project",
|
||||
"node_id": "UUID for the node"
|
||||
"project_id": "Project UUID",
|
||||
"node_id": "Node UUID"
|
||||
},
|
||||
status_codes={
|
||||
201: "Instance deleted",
|
||||
400: "Invalid request"
|
||||
204: "Instance deleted",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Delete a node instance")
|
||||
def delete(request, response):
|
||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||
node = project.get_node(request.match_info["node_id"])
|
||||
yield from node.destroy()
|
||||
response.set_status(201)
|
||||
response.set_status(204)
|
||||
@@ -19,10 +19,13 @@ import aiohttp
|
||||
import asyncio
|
||||
|
||||
|
||||
from ....web.route import Route
|
||||
from ....schemas.project import PROJECT_OBJECT_SCHEMA, PROJECT_CREATE_SCHEMA
|
||||
from ....controller import Controller
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.controller import Controller
|
||||
|
||||
from gns3server.schemas.project import (
|
||||
PROJECT_OBJECT_SCHEMA,
|
||||
PROJECT_CREATE_SCHEMA
|
||||
)
|
||||
|
||||
import logging
|
||||
log = logging.getLogger()
|
||||
@@ -30,7 +33,6 @@ log = logging.getLogger()
|
||||
|
||||
class ProjectHandler:
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects",
|
||||
description="Create a new project on the server",
|
||||
@@ -43,15 +45,13 @@ class ProjectHandler:
|
||||
def create_project(request, response):
|
||||
|
||||
controller = Controller.instance()
|
||||
project = yield from controller.addProject(
|
||||
name=request.json.get("name"),
|
||||
path=request.json.get("path"),
|
||||
project_id=request.json.get("project_id"),
|
||||
temporary=request.json.get("temporary", False))
|
||||
project = yield from controller.add_project(name=request.json.get("name"),
|
||||
path=request.json.get("path"),
|
||||
project_id=request.json.get("project_id"),
|
||||
temporary=request.json.get("temporary", False))
|
||||
response.set_status(201)
|
||||
response.json(project)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects",
|
||||
description="List projects",
|
||||
@@ -60,17 +60,16 @@ class ProjectHandler:
|
||||
})
|
||||
def list_projects(request, response):
|
||||
controller = Controller.instance()
|
||||
response.json([ p for p in controller.projects.values() ])
|
||||
response.json([p for p in controller.projects.values()])
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}",
|
||||
description="Get the project",
|
||||
description="Get a project",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "The project exist",
|
||||
200: "Project information returned",
|
||||
404: "The project doesn't exist"
|
||||
})
|
||||
def get(request, response):
|
||||
@@ -78,12 +77,11 @@ class ProjectHandler:
|
||||
project = controller.get_project(request.match_info["project_id"])
|
||||
response.json(project)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/commit",
|
||||
description="Write changes on disk",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Changes have been written on disk",
|
||||
@@ -96,12 +94,11 @@ class ProjectHandler:
|
||||
yield from project.commit()
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/close",
|
||||
description="Close a project",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "The project has been closed",
|
||||
@@ -115,12 +112,11 @@ class ProjectHandler:
|
||||
controller.remove_project(project)
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.delete(
|
||||
r"/projects/{project_id}",
|
||||
description="Delete a project from disk",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
204: "Changes have been written on disk",
|
||||
@@ -134,12 +130,11 @@ class ProjectHandler:
|
||||
controller.remove_project(project)
|
||||
response.set_status(204)
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/notifications",
|
||||
description="Receive notifications about the projects",
|
||||
description="Receive notifications about projects",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "End of stream",
|
||||
@@ -153,7 +148,7 @@ class ProjectHandler:
|
||||
response.content_type = "application/json"
|
||||
response.set_status(200)
|
||||
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.start(request)
|
||||
@@ -165,12 +160,11 @@ class ProjectHandler:
|
||||
except asyncio.futures.CancelledError as e:
|
||||
break
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/notifications/ws",
|
||||
description="Receive notifications about the projects via Websocket",
|
||||
description="Receive notifications about projects from a Websocket",
|
||||
parameters={
|
||||
"project_id": "The UUID of the project",
|
||||
"project_id": "Project UUID",
|
||||
},
|
||||
status_codes={
|
||||
200: "End of stream",
|
||||
@@ -187,8 +181,8 @@ class ProjectHandler:
|
||||
with project.queue() as queue:
|
||||
while True:
|
||||
try:
|
||||
notif = yield from queue.get_json(5)
|
||||
notification = yield from queue.get_json(5)
|
||||
except asyncio.futures.CancelledError as e:
|
||||
break
|
||||
ws.send_str(notif)
|
||||
ws.send_str(notification)
|
||||
return ws
|
||||
@@ -15,16 +15,15 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from ....web.route import Route
|
||||
from ....config import Config
|
||||
from ....schemas.version import VERSION_SCHEMA
|
||||
from ....version import __version__
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.config import Config
|
||||
from gns3server.schemas.version import VERSION_SCHEMA
|
||||
from gns3server.version import __version__
|
||||
from aiohttp.web import HTTPConflict
|
||||
|
||||
|
||||
class VersionHandler:
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/version",
|
||||
description="Retrieve the server version number",
|
||||
@@ -35,7 +34,6 @@ class VersionHandler:
|
||||
local_server = config.get_section_config("Server").getboolean("local", False)
|
||||
response.json({"version": __version__, "local": local_server})
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/version",
|
||||
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
|
||||
# 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/>.
|
||||
|
||||
|
||||
from ..web.route import Route
|
||||
from ..controller import Controller
|
||||
from ..compute.port_manager import PortManager
|
||||
from ..compute.project_manager import ProjectManager
|
||||
from ..version import __version__
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.controller import Controller
|
||||
from gns3server.compute.port_manager import PortManager
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
from gns3server.version import __version__
|
||||
|
||||
|
||||
class IndexHandler:
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/",
|
||||
description="Home page for GNS3Server"
|
||||
description="Home page of the GNS3 server"
|
||||
)
|
||||
def index(request, response):
|
||||
response.template("index.html")
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/compute",
|
||||
description="Ressources used by GNS3 Compute"
|
||||
description="Resources used by the GNS3 compute servers"
|
||||
)
|
||||
def compute(request, response):
|
||||
response.template("compute.html",
|
||||
port_manager=PortManager.instance(),
|
||||
project_manager=ProjectManager.instance()
|
||||
)
|
||||
project_manager=ProjectManager.instance())
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/controller",
|
||||
description="Ressources used by GNS3 Controller"
|
||||
description="Resources used by the GNS3 controller server"
|
||||
)
|
||||
def controller(request, response):
|
||||
response.template("controller.html",
|
||||
controller=Controller.instance()
|
||||
)
|
||||
controller=Controller.instance())
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/projects/{project_id}",
|
||||
description="Ressources used by GNS3 Controller"
|
||||
description="List of the GNS3 projects"
|
||||
)
|
||||
def project(request, response):
|
||||
controller = Controller.instance()
|
||||
response.template("project.html",
|
||||
project=controller.get_project(request.match_info["project_id"]))
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/v1/version",
|
||||
description="Old API"
|
||||
description="Old 1.0 API"
|
||||
)
|
||||
def get_v1(request, response):
|
||||
response.json({"version": __version__})
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- 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
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -22,17 +22,16 @@ import io
|
||||
import tarfile
|
||||
import asyncio
|
||||
|
||||
from ..config import Config
|
||||
from ..web.route import Route
|
||||
from ..utils.images import remove_checksum, md5sum
|
||||
from gns3server.config import Config
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.utils.images import remove_checksum, md5sum
|
||||
|
||||
|
||||
class UploadHandler:
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/upload",
|
||||
description="Manage upload of GNS3 images",
|
||||
description="List binary images",
|
||||
api_version=None
|
||||
)
|
||||
def index(request, response):
|
||||
@@ -50,10 +49,9 @@ class UploadHandler:
|
||||
uploaded_files.append(iourc_path)
|
||||
response.template("upload.html", files=uploaded_files)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/upload",
|
||||
description="Manage upload of GNS3 images",
|
||||
description="Upload binary images",
|
||||
api_version=None
|
||||
)
|
||||
def upload(request, response):
|
||||
@@ -95,16 +93,14 @@ class UploadHandler:
|
||||
return
|
||||
response.redirect("/upload")
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/backup/images.tar",
|
||||
description="Backup GNS3 images",
|
||||
description="Backup binary images",
|
||||
api_version=None
|
||||
)
|
||||
def backup_images(request, response):
|
||||
yield from UploadHandler._backup_directory(request, response, UploadHandler.image_directory())
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/backup/projects.tar",
|
||||
description="Backup GNS3 projects",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
NODE_LIST_IMAGES_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "List of disk images",
|
||||
"description": "List of binary images",
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user