mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-24 17:28:08 +00:00
Handlers: cleanup and fixes.
This commit is contained in:
parent
885d93be02
commit
f81d35cc29
@ -22,7 +22,6 @@ Docker server module.
|
||||
import asyncio
|
||||
import 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,7 +49,7 @@ 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"),
|
||||
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"),
|
||||
@ -77,19 +63,18 @@ class DockerHandler:
|
||||
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",
|
||||
@ -78,12 +83,11 @@ class DynamipsVMHandler:
|
||||
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"],
|
||||
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"),
|
||||
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": [
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ def test_vboxmanage_path(manager, tmpdir):
|
||||
assert manager.find_vboxmanage() == path
|
||||
|
||||
|
||||
def test_list_images(manager, loop):
|
||||
def test_list_vms(manager, loop):
|
||||
vm_list = ['"Windows 8.1" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
||||
'"Carriage',
|
||||
'Return" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
||||
@ -92,7 +92,7 @@ def test_list_images(manager, loop):
|
||||
|
||||
with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute") as mock:
|
||||
mock.side_effect = execute_mock
|
||||
vms = loop.run_until_complete(asyncio.async(manager.list_images()))
|
||||
vms = loop.run_until_complete(asyncio.async(manager.list_vms()))
|
||||
assert vms == [
|
||||
{"vmname": "Windows 8.1", "ram": 512},
|
||||
{"vmname": "Linux Microcore 4.7.1", "ram": 256}
|
||||
|
@ -121,18 +121,18 @@ def test_addProject(controller, async_run):
|
||||
uuid1 = str(uuid.uuid4())
|
||||
uuid2 = str(uuid.uuid4())
|
||||
|
||||
async_run(controller.addProject(project_id=uuid1))
|
||||
async_run(controller.add_project(project_id=uuid1))
|
||||
assert len(controller.projects) == 1
|
||||
async_run(controller.addProject(project_id=uuid1))
|
||||
async_run(controller.add_project(project_id=uuid1))
|
||||
assert len(controller.projects) == 1
|
||||
async_run(controller.addProject(project_id=uuid2))
|
||||
async_run(controller.add_project(project_id=uuid2))
|
||||
assert len(controller.projects) == 2
|
||||
|
||||
|
||||
def test_remove_project(controller, async_run):
|
||||
uuid1 = str(uuid.uuid4())
|
||||
|
||||
project1 = async_run(controller.addProject(project_id=uuid1))
|
||||
project1 = async_run(controller.add_project(project_id=uuid1))
|
||||
assert len(controller.projects) == 1
|
||||
|
||||
controller.remove_project(project1)
|
||||
@ -146,13 +146,13 @@ def test_addProject_with_compute(controller, async_run):
|
||||
compute.post = MagicMock()
|
||||
controller._computes = {"test1": compute}
|
||||
|
||||
project1 = async_run(controller.addProject(project_id=uuid1))
|
||||
project1 = async_run(controller.add_project(project_id=uuid1))
|
||||
|
||||
|
||||
def test_getProject(controller, async_run):
|
||||
uuid1 = str(uuid.uuid4())
|
||||
|
||||
project = async_run(controller.addProject(project_id=uuid1))
|
||||
project = async_run(controller.add_project(project_id=uuid1))
|
||||
assert controller.get_project(uuid1) == project
|
||||
with pytest.raises(aiohttp.web.HTTPNotFound):
|
||||
assert controller.get_project("dsdssd")
|
||||
|
@ -96,9 +96,16 @@ def test_docker_delete(http_compute, vm):
|
||||
assert response.status == 204
|
||||
|
||||
|
||||
def test_docker_reload(http_compute, vm):
|
||||
def test_docker_pause(http_compute, vm):
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.pause", return_value=True) as mock:
|
||||
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/pause".format(project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status == 204
|
||||
|
||||
|
||||
def test_docker_unpause(http_compute, vm):
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.unpause", return_value=True) as mock:
|
||||
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/unpause".format(project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status == 204
|
||||
|
||||
|
@ -151,17 +151,17 @@ def fake_file(tmpdir):
|
||||
return path
|
||||
|
||||
|
||||
def test_vms(http_compute, tmpdir, fake_dynamips, fake_file):
|
||||
def test_images(http_compute, tmpdir, fake_dynamips, fake_file):
|
||||
|
||||
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir), example=True):
|
||||
response = http_compute.get("/dynamips/nodes")
|
||||
response = http_compute.get("/dynamips/images")
|
||||
assert response.status == 200
|
||||
assert response.json == [{"filename": "7200.bin", "path": "7200.bin"}]
|
||||
|
||||
|
||||
def test_upload_vm(http_compute, tmpdir):
|
||||
def test_upload_image(http_compute, tmpdir):
|
||||
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir),):
|
||||
response = http_compute.post("/dynamips/nodes/test2", body="TEST", raw=True)
|
||||
response = http_compute.post("/dynamips/images/test2", body="TEST", raw=True)
|
||||
assert response.status == 204
|
||||
|
||||
with open(str(tmpdir / "test2")) as f:
|
||||
@ -172,11 +172,11 @@ def test_upload_vm(http_compute, tmpdir):
|
||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||
|
||||
|
||||
def test_upload_vm_permission_denied(http_compute, tmpdir):
|
||||
def test_upload_image_permission_denied(http_compute, tmpdir):
|
||||
with open(str(tmpdir / "test2.tmp"), "w+") as f:
|
||||
f.write("")
|
||||
os.chmod(str(tmpdir / "test2.tmp"), 0)
|
||||
|
||||
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir),):
|
||||
response = http_compute.post("/dynamips/nodes/test2", body="TEST", raw=True)
|
||||
response = http_compute.post("/dynamips/images/test2", body="TEST", raw=True)
|
||||
assert response.status == 409
|
||||
|
@ -328,17 +328,17 @@ def test_get_configs_with_startup_config_file(http_compute, project, vm):
|
||||
assert response.json["startup_config_content"] == "TEST"
|
||||
|
||||
|
||||
def test_vms(http_compute, tmpdir, fake_iou_bin):
|
||||
def test_images(http_compute, tmpdir, fake_iou_bin):
|
||||
|
||||
with patch("gns3server.compute.IOU.get_images_directory", return_value=str(tmpdir)):
|
||||
response = http_compute.get("/iou/nodes", example=True)
|
||||
response = http_compute.get("/iou/images", example=True)
|
||||
assert response.status == 200
|
||||
assert response.json == [{"filename": "iou.bin", "path": "iou.bin"}]
|
||||
|
||||
|
||||
def test_upload_vm(http_compute, tmpdir):
|
||||
def test_image_vm(http_compute, tmpdir):
|
||||
with patch("gns3server.compute.IOU.get_images_directory", return_value=str(tmpdir),):
|
||||
response = http_compute.post("/iou/nodes/test2", body="TEST", raw=True)
|
||||
response = http_compute.post("/iou/images/test2", body="TEST", raw=True)
|
||||
assert response.status == 204
|
||||
|
||||
with open(str(tmpdir / "test2")) as f:
|
||||
|
@ -224,16 +224,16 @@ def test_qemu_list_binaries_filter(http_compute, vm):
|
||||
assert response.json == ret
|
||||
|
||||
|
||||
def test_vms(http_compute, tmpdir, fake_qemu_vm):
|
||||
def test_images(http_compute, tmpdir, fake_qemu_vm):
|
||||
|
||||
response = http_compute.get("/qemu/nodes")
|
||||
response = http_compute.get("/qemu/images")
|
||||
assert response.status == 200
|
||||
assert response.json == [{"filename": "linux载.img", "path": "linux载.img"}]
|
||||
|
||||
|
||||
def test_upload_vm(http_compute, tmpdir):
|
||||
def test_upload_image(http_compute, tmpdir):
|
||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
||||
response = http_compute.post("/qemu/nodes/test2", body="TEST", raw=True)
|
||||
response = http_compute.post("/qemu/images/test2", body="TEST", raw=True)
|
||||
assert response.status == 204
|
||||
|
||||
with open(str(tmpdir / "test2")) as f:
|
||||
@ -244,9 +244,9 @@ def test_upload_vm(http_compute, tmpdir):
|
||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||
|
||||
|
||||
def test_upload_vm_ova(http_compute, tmpdir):
|
||||
def test_upload_image_ova(http_compute, tmpdir):
|
||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
||||
response = http_compute.post("/qemu/nodes/test2.ova/test2.vmdk", body="TEST", raw=True)
|
||||
response = http_compute.post("/qemu/images/test2.ova/test2.vmdk", body="TEST", raw=True)
|
||||
assert response.status == 204
|
||||
|
||||
with open(str(tmpdir / "test2.ova" / "test2.vmdk")) as f:
|
||||
@ -257,19 +257,19 @@ def test_upload_vm_ova(http_compute, tmpdir):
|
||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||
|
||||
|
||||
def test_upload_vm_forbiden_location(http_compute, tmpdir):
|
||||
def test_upload_image_forbiden_location(http_compute, tmpdir):
|
||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
||||
response = http_compute.post("/qemu/nodes/../../test2", body="TEST", raw=True)
|
||||
response = http_compute.post("/qemu/images/../../test2", body="TEST", raw=True)
|
||||
assert response.status == 403
|
||||
|
||||
|
||||
def test_upload_vm_permission_denied(http_compute, tmpdir):
|
||||
def test_upload_image_permission_denied(http_compute, tmpdir):
|
||||
with open(str(tmpdir / "test2.tmp"), "w+") as f:
|
||||
f.write("")
|
||||
os.chmod(str(tmpdir / "test2.tmp"), 0)
|
||||
|
||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
|
||||
response = http_compute.post("/qemu/nodes/test2", body="TEST", raw=True)
|
||||
response = http_compute.post("/qemu/images/test2", body="TEST", raw=True)
|
||||
assert response.status == 409
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ def compute(http_controller, async_run):
|
||||
|
||||
@pytest.fixture
|
||||
def project(http_controller, async_run):
|
||||
return async_run(Controller.instance().addProject())
|
||||
return async_run(Controller.instance().add_project())
|
||||
|
||||
|
||||
def test_create_link(http_controller, tmpdir, project, compute, async_run):
|
||||
|
@ -44,7 +44,7 @@ def compute(http_controller, async_run):
|
||||
|
||||
@pytest.fixture
|
||||
def project(http_controller, async_run):
|
||||
return async_run(Controller.instance().addProject())
|
||||
return async_run(Controller.instance().add_project())
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -103,7 +103,7 @@ def test_update_node(http_controller, tmpdir, project, compute, node):
|
||||
"startup_script": "echo test"
|
||||
}
|
||||
}, example=True)
|
||||
assert response.status == 201
|
||||
assert response.status == 200
|
||||
assert response.json["name"] == "test"
|
||||
assert "name" not in response.json["properties"]
|
||||
|
||||
@ -113,17 +113,14 @@ def test_start_node(http_controller, tmpdir, project, compute, node):
|
||||
compute.post = AsyncioMagicMock()
|
||||
|
||||
response = http_controller.post("/projects/{}/nodes/{}/start".format(project.id, node.id), example=True)
|
||||
assert response.status == 201
|
||||
assert response.json["name"] == node.name
|
||||
|
||||
assert response.status == 204
|
||||
|
||||
def test_stop_node(http_controller, tmpdir, project, compute, node):
|
||||
response = MagicMock()
|
||||
compute.post = AsyncioMagicMock()
|
||||
|
||||
response = http_controller.post("/projects/{}/nodes/{}/stop".format(project.id, node.id), example=True)
|
||||
assert response.status == 201
|
||||
assert response.json["name"] == node.name
|
||||
assert response.status == 204
|
||||
|
||||
|
||||
def test_suspend_node(http_controller, tmpdir, project, compute, node):
|
||||
@ -131,8 +128,7 @@ def test_suspend_node(http_controller, tmpdir, project, compute, node):
|
||||
compute.post = AsyncioMagicMock()
|
||||
|
||||
response = http_controller.post("/projects/{}/nodes/{}/suspend".format(project.id, node.id), example=True)
|
||||
assert response.status == 201
|
||||
assert response.json["name"] == node.name
|
||||
assert response.status == 204
|
||||
|
||||
|
||||
def test_reload_node(http_controller, tmpdir, project, compute, node):
|
||||
@ -140,8 +136,7 @@ def test_reload_node(http_controller, tmpdir, project, compute, node):
|
||||
compute.post = AsyncioMagicMock()
|
||||
|
||||
response = http_controller.post("/projects/{}/nodes/{}/reload".format(project.id, node.id), example=True)
|
||||
assert response.status == 201
|
||||
assert response.json["name"] == node.name
|
||||
assert response.status == 204
|
||||
|
||||
|
||||
def test_delete_node(http_controller, tmpdir, project, compute, node):
|
||||
@ -149,4 +144,4 @@ def test_delete_node(http_controller, tmpdir, project, compute, node):
|
||||
compute.post = AsyncioMagicMock()
|
||||
|
||||
response = http_controller.delete("/projects/{}/nodes/{}".format(project.id, node.id), example=True)
|
||||
assert response.status == 201
|
||||
assert response.status == 204
|
||||
|
@ -33,7 +33,7 @@ def test_index(http_root):
|
||||
|
||||
|
||||
def test_controller(http_root, async_run):
|
||||
project = async_run(Controller.instance().addProject(name="test"))
|
||||
project = async_run(Controller.instance().add_project(name="test"))
|
||||
response = http_root.get('/controller')
|
||||
assert "test" in response.html
|
||||
assert response.status == 200
|
||||
@ -45,7 +45,7 @@ def test_compute(http_root):
|
||||
|
||||
|
||||
def test_project(http_root, async_run):
|
||||
project = async_run(Controller.instance().addProject(name="test"))
|
||||
project = async_run(Controller.instance().add_project(name="test"))
|
||||
response = http_root.get('/projects/{}'.format(project.id))
|
||||
assert response.status == 200
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user