Migration to FastAPI

This commit is contained in:
grossmj committed 2020-10-02 16:07:50 +09:30
1 parent c12b675691
commit eb3cb8a41f
224 files changed
+11254 -13517

No files matched your search

@@ -1,43 +0,0 @@
#!/usr/bin/env python
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
from .capabilities_handler import CapabilitiesHandler
from .network_handler import NetworkHandler
from .project_handler import ProjectHandler
from .dynamips_vm_handler import DynamipsVMHandler
from .qemu_handler import QEMUHandler
from .virtualbox_handler import VirtualBoxHandler
from .vpcs_handler import VPCSHandler
from .vmware_handler import VMwareHandler
from .server_handler import ServerHandler
from .notification_handler import NotificationHandler
from .cloud_handler import CloudHandler
from .nat_handler import NatHandler
from .ethernet_hub_handler import EthernetHubHandler
from .ethernet_switch_handler import EthernetSwitchHandler
from .frame_relay_switch_handler import FrameRelaySwitchHandler
from .atm_switch_handler import ATMSwitchHandler
from .traceng_handler import TraceNGHandler
if sys.platform.startswith("linux") or hasattr(sys, "_called_from_test") or os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1":
# IOU & Docker only runs on Linux but test suite works on UNIX platform
if not sys.platform.startswith("win"):
from .iou_handler import IOUHandler
from .docker_handler import DockerHandler
@@ -1,312 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from gns3server.web.route import Route
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
from gns3server.schemas.nio import NIO_SCHEMA
from gns3server.compute.dynamips import Dynamips
from gns3server.schemas.atm_switch import (
ATM_SWITCH_CREATE_SCHEMA,
ATM_SWITCH_OBJECT_SCHEMA,
ATM_SWITCH_UPDATE_SCHEMA
)
class ATMSwitchHandler:
"""
API entry points for ATM switch.
"""
@Route.post(
r"/projects/{project_id}/atm_switch/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new ATM switch instance",
input=ATM_SWITCH_CREATE_SCHEMA,
output=ATM_SWITCH_OBJECT_SCHEMA)
async def create(request, response):
# Use the Dynamips ATM switch to simulate this node
dynamips_manager = Dynamips.instance()
node = await dynamips_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
node_type="atm_switch",
mappings=request.json.get("mappings"))
response.set_status(201)
response.json(node)
@Route.get(
r"/projects/{project_id}/atm_switch/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get an ATM switch instance",
output=ATM_SWITCH_OBJECT_SCHEMA)
def show(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(node)
@Route.post(
r"/projects/{project_id}/atm_switch/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate an atm switch instance")
async def duplicate(request, response):
new_node = await Dynamips.instance().duplicate_node(
request.match_info["node_id"],
request.json["destination_node_id"]
)
response.set_status(201)
response.json(new_node)
@Route.put(
r"/projects/{project_id}/atm_switch/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update an ATM switch instance",
input=ATM_SWITCH_UPDATE_SCHEMA,
output=ATM_SWITCH_OBJECT_SCHEMA)
async def update(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
if "name" in request.json and node.name != request.json["name"]:
await node.set_name(request.json["name"])
if "mappings" in request.json:
node.mappings = request.json["mappings"]
node.updated()
response.json(node)
@Route.delete(
r"/projects/{project_id}/atm_switch/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete an ATM switch instance")
async def delete(request, response):
dynamips_manager = Dynamips.instance()
await dynamips_manager.delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/atm_switch/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start an ATM switch")
def start(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/atm_switch/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop an ATM switch")
def stop(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/atm_switch/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend an ATM Relay switch (does nothing)")
def suspend(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/atm_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to an ATM switch instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
nio = await dynamips_manager.create_nio(node, request.json)
port_number = int(request.match_info["port_number"])
await node.add_nio(nio, port_number)
response.set_status(201)
response.json(nio)
@Route.delete(
r"/projects/{project_id}/atm_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from an ATM switch instance")
async def delete_nio(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = await node.remove_nio(port_number)
await nio.delete()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/atm_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a packet capture on an ATM switch instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(node.project.capture_working_directory(), request.json["capture_file_name"])
await node.start_capture(port_number, pcap_file_path, request.json["data_link_type"])
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/atm_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a packet capture on an ATM switch instance")
async def stop_capture(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await node.stop_capture(port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/atm_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture (always 0)",
"port_number": "Port on the switch"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = node.get_nio(port_number)
await dynamips_manager.stream_pcap_file(nio, node.project.id, request, response)
@@ -1,47 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import psutil
from gns3server.web.route import Route
from gns3server.schemas.capabilities import CAPABILITIES_SCHEMA
from gns3server.version import __version__
from gns3server.compute import MODULES
from gns3server.utils.path import get_default_project_directory
class CapabilitiesHandler:
@Route.get(
r"/capabilities",
description="Retrieve the capabilities of the server",
output=CAPABILITIES_SCHEMA)
def get(request, response):
node_types = []
for module in MODULES:
node_types.extend(module.node_types())
response.json({
"version": __version__,
"platform": sys.platform,
"cpus": psutil.cpu_count(logical=True),
"memory": psutil.virtual_memory().total,
"disk_size": psutil.disk_usage(get_default_project_directory()).total,
"node_types": node_types
})
@@ -1,326 +0,0 @@
# -*- coding: utf-8 -*-
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from aiohttp.web import HTTPConflict
from gns3server.web.route import Route
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
from gns3server.schemas.nio import NIO_SCHEMA
from gns3server.compute.builtin import Builtin
from gns3server.schemas.cloud import (
CLOUD_CREATE_SCHEMA,
CLOUD_OBJECT_SCHEMA,
CLOUD_UPDATE_SCHEMA
)
class CloudHandler:
"""
API entry points for cloud
"""
@Route.post(
r"/projects/{project_id}/cloud/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new cloud instance",
input=CLOUD_CREATE_SCHEMA,
output=CLOUD_OBJECT_SCHEMA)
async def create(request, response):
builtin_manager = Builtin.instance()
node = await builtin_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
node_type="cloud",
ports=request.json.get("ports_mapping"))
# add the remote console settings
node.remote_console_host = request.json.get("remote_console_host", node.remote_console_host)
node.remote_console_port = request.json.get("remote_console_port", node.remote_console_port)
node.remote_console_type = request.json.get("remote_console_type", node.remote_console_type)
node.remote_console_http_path = request.json.get("remote_console_http_path", node.remote_console_http_path)
node.usage = request.json.get("usage", "")
response.set_status(201)
response.json(node)
@Route.get(
r"/projects/{project_id}/cloud/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a cloud instance",
output=CLOUD_OBJECT_SCHEMA)
def show(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(node)
@Route.put(
r"/projects/{project_id}/cloud/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a cloud instance",
input=CLOUD_UPDATE_SCHEMA,
output=CLOUD_OBJECT_SCHEMA)
def update(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
for name, value in request.json.items():
if hasattr(node, name) and getattr(node, name) != value:
setattr(node, name, value)
node.updated()
response.json(node)
@Route.delete(
r"/projects/{project_id}/cloud/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a cloud instance")
async def delete(request, response):
builtin_manager = Builtin.instance()
await builtin_manager.delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/cloud/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a cloud")
async def start(request, response):
node = Builtin.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await node.start()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/cloud/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a cloud")
def stop(request, response):
Builtin.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/cloud/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a cloud (does nothing)")
def suspend(request, response):
Builtin.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/cloud/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the cloud (always 0)",
"port_number": "Port on the cloud"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a cloud instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
nio = builtin_manager.create_nio(request.json)
port_number = int(request.match_info["port_number"])
await node.add_nio(nio, port_number)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/cloud/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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 updated"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO on a Cloud instance")
async def update_nio(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = node.get_nio(port_number)
if "filters" in request.json:
nio.filters = request.json["filters"]
await node.update_nio(port_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/cloud/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the cloud (always 0)",
"port_number": "Port on the cloud"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a cloud instance")
async def delete_nio(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await node.remove_nio(port_number)
response.set_status(204)
@Route.post(
r"/projects/{project_id}/cloud/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the cloud (always 0)",
"port_number": "Port on the cloud"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a packet capture on a cloud instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(node.project.capture_working_directory(), request.json["capture_file_name"])
await node.start_capture(port_number, pcap_file_path, request.json["data_link_type"])
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/cloud/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the cloud (always 0)",
"port_number": "Port on the cloud"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a packet capture on a cloud instance")
async def stop_capture(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await node.stop_capture(port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/cloud/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture (always 0)",
"port_number": "Port on the cloud"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = node.get_nio(port_number)
await builtin_manager.stream_pcap_file(nio, node.project.id, request, response)
@@ -1,451 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from aiohttp.web import HTTPConflict
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 gns3server.schemas.docker import (
DOCKER_CREATE_SCHEMA,
DOCKER_OBJECT_SCHEMA,
DOCKER_LIST_IMAGES_SCHEMA
)
class DockerHandler:
"""API entry points for Docker containers."""
@Route.post(
r"/projects/{project_id}/docker/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new Docker container",
input=DOCKER_CREATE_SCHEMA,
output=DOCKER_OBJECT_SCHEMA)
async def create(request, response):
docker_manager = Docker.instance()
container = await docker_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
image=request.json.pop("image"),
start_command=request.json.get("start_command"),
environment=request.json.get("environment"),
adapters=request.json.get("adapters"),
console=request.json.get("console"),
console_type=request.json.get("console_type"),
console_resolution=request.json.get("console_resolution", "1024x768"),
console_http_port=request.json.get("console_http_port", 80),
console_http_path=request.json.get("console_http_path", "/"),
aux=request.json.get("aux"),
aux_type=request.json.pop("aux_type", "none"),
extra_hosts=request.json.get("extra_hosts"),
extra_volumes=request.json.get("extra_volumes"),
memory=request.json.get("memory", 0),
cpus=request.json.get("cpus", 0))
for name, value in request.json.items():
if name != "node_id":
if hasattr(container, name) and getattr(container, name) != value:
setattr(container, name, value)
response.set_status(201)
response.json(container)
@Route.post(
r"/projects/{project_id}/docker/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a Docker container")
async def start(request, response):
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await container.start()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/docker/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a Docker container")
async def stop(request, response):
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await container.stop()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/docker/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a Docker container")
async def suspend(request, response):
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await container.pause()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/docker/nodes/{node_id}/reload",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance restarted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Restart a Docker container")
async def reload(request, response):
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await container.restart()
response.set_status(204)
@Route.delete(
r"/projects/{project_id}/docker/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a Docker container")
async def delete(request, response):
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await container.delete()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/docker/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate a Docker instance")
async def duplicate(request, response):
new_node = await Docker.instance().duplicate_node(
request.match_info["node_id"],
request.json["destination_node_id"]
)
response.set_status(201)
response.json(new_node)
@Route.post(
r"/projects/{project_id}/docker/nodes/{node_id}/pause",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance paused",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Pause a Docker container")
async def pause(request, response):
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await 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")
async 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"])
await 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": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter where the nio should be added",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a Docker container",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
docker_manager = Docker.instance()
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 != "nio_udp":
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
adapter_number = int(request.match_info["adapter_number"])
nio = docker_manager.create_nio(request.json)
await container.adapter_add_nio_binding(adapter_number, nio)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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 updated (always 0)"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO on a Docker instance")
async def update_nio(request, response):
docker_manager = Docker.instance()
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"])
nio = container.get_nio(adapter_number)
if "filters" in request.json and nio:
nio.filters = request.json["filters"]
await container.adapter_update_nio_binding(adapter_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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)"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a Docker container")
async def delete_nio(request, response):
docker_manager = Docker.instance()
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"])
await container.adapter_remove_nio_binding(adapter_number)
response.set_status(204)
@Route.put(
r"/projects/{project_id}/docker/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a Docker instance",
input=DOCKER_OBJECT_SCHEMA,
output=DOCKER_OBJECT_SCHEMA)
async def update(request, response):
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
props = [
"name", "console", "console_type", "aux", "aux_type", "console_resolution",
"console_http_port", "console_http_path", "start_command",
"environment", "adapters", "extra_hosts", "extra_volumes",
"memory", "cpus"
]
changed = False
for prop in props:
if prop in request.json and request.json[prop] != getattr(container, prop):
setattr(container, prop, request.json[prop])
changed = True
# We don't call container.update for nothing because it will restart the container
if changed:
await container.update()
container.updated()
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": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to start a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Node not started"
},
description="Start a packet capture on a Docker container instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
docker_manager = Docker.instance()
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(container.project.capture_working_directory(), request.json["capture_file_name"])
await 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": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to stop a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Container not started"
},
description="Stop a packet capture on a Docker container instance")
async def stop_capture(request, response):
docker_manager = Docker.instance()
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"])
await container.stop_capture(adapter_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
docker_manager = Docker.instance()
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"])
nio = container.get_nio(adapter_number)
await docker_manager.stream_pcap_file(nio, container.project.id, request, response)
@Route.get(
r"/docker/images",
status_codes={
200: "Success",
},
output=DOCKER_LIST_IMAGES_SCHEMA,
description="Get all available Docker images")
async def show(request, response):
docker_manager = Docker.instance()
images = await docker_manager.list_images()
response.json(images)
@Route.get(
r"/projects/{project_id}/docker/nodes/{node_id}/console/ws",
description="WebSocket for console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
})
async def console_ws(request, response):
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
return await container.start_websocket_console(request)
@Route.post(
r"/projects/{project_id}/docker/nodes/{node_id}/console/reset",
description="Reset console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Console has been reset",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Container not started"
})
async def reset_console(request, response):
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await container.reset_console()
response.set_status(204)
@@ -1,548 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import aiohttp
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
)
DEFAULT_CHASSIS = {
"c1700": "1720",
"c2600": "2610",
"c3600": "3640"
}
class DynamipsVMHandler:
"""
API entry points for Dynamips VMs.
"""
@Route.post(
r"/projects/{project_id}/dynamips/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new Dynamips VM instance",
input=VM_CREATE_SCHEMA,
output=VM_OBJECT_SCHEMA)
async def create(request, response):
dynamips_manager = Dynamips.instance()
platform = request.json.pop("platform")
default_chassis = None
if platform in DEFAULT_CHASSIS:
default_chassis = DEFAULT_CHASSIS[platform]
vm = await dynamips_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
dynamips_id=request.json.get("dynamips_id"),
platform=platform,
console=request.json.get("console"),
console_type=request.json.get("console_type", "telnet"),
aux=request.json.get("aux"),
aux_type=request.json.pop("aux_type", "none"),
chassis=request.json.pop("chassis", default_chassis),
node_type="dynamips")
await dynamips_manager.update_vm_settings(vm, request.json)
response.set_status(201)
response.json(vm)
@Route.get(
r"/projects/{project_id}/dynamips/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a Dynamips VM instance",
output=VM_OBJECT_SCHEMA)
def show(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(vm)
@Route.put(
r"/projects/{project_id}/dynamips/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a Dynamips VM instance",
input=VM_UPDATE_SCHEMA,
output=VM_OBJECT_SCHEMA)
async def update(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await dynamips_manager.update_vm_settings(vm, request.json)
vm.updated()
response.json(vm)
@Route.delete(
r"/projects/{project_id}/dynamips/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a Dynamips VM instance")
async def delete(request, response):
# check the project_id exists
ProjectManager.instance().get_project(request.match_info["project_id"])
await Dynamips.instance().delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a Dynamips VM instance")
async def start(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
try:
await dynamips_manager.ghost_ios_support(vm)
except GeneratorExit:
pass
await vm.start()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a Dynamips VM instance")
async def stop(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.stop()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a Dynamips VM instance")
async def suspend(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.suspend()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/resume",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance resumed",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Resume a suspended Dynamips VM instance")
async def resume(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.resume()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/reload",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance reloaded",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Reload a Dynamips VM instance")
async def reload(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reload()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter where the nio should be added",
"port_number": "Port on the adapter"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a Dynamips VM instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
nio = await dynamips_manager.create_nio(vm, request.json)
slot_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
await vm.slot_add_nio_binding(slot_number, port_number, nio)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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 updated"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO on a Dynamips instance")
async def update_nio(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
slot_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
nio = vm.get_nio(slot_number, port_number)
if "filters" in request.json:
nio.filters = request.json["filters"]
await vm.slot_update_nio_binding(slot_number, port_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter from where the nio should be removed",
"port_number": "Port on the adapter"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a Dynamips VM instance")
async def delete_nio(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
slot_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
nio = await vm.slot_remove_nio_binding(slot_number, port_number)
await nio.delete()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to start a packet capture",
"port_number": "Port on the adapter"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a packet capture on a Dynamips VM instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
slot_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(vm.project.capture_working_directory(), request.json["capture_file_name"])
if sys.platform.startswith('win'):
# FIXME: Dynamips (Cygwin actually) doesn't like non ascii paths on Windows
try:
pcap_file_path.encode('ascii')
except UnicodeEncodeError:
raise DynamipsError('The capture file path "{}" must only contain ASCII (English) characters'.format(pcap_file_path))
await vm.start_capture(slot_number, port_number, pcap_file_path, request.json["data_link_type"])
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to stop a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a packet capture on a Dynamips VM instance")
async def stop_capture(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
slot_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
await vm.stop_capture(slot_number, port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
slot_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
nio = vm.get_nio(slot_number, port_number)
await dynamips_manager.stream_pcap_file(nio, vm.project.id, request, response)
@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",
404: "Instance doesn't exist"
},
description="Retrieve the idlepc proposals")
async def get_idlepcs(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.set_idlepc("0x0")
idlepcs = await vm.get_idle_pc_prop()
response.set_status(200)
response.json(idlepcs)
@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",
404: "Instance doesn't exist"
},
description="Retrieve the idlepc proposals")
async def get_auto_idlepc(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
idlepc = await dynamips_manager.auto_idlepc(vm)
response.set_status(200)
response.json({"idlepc": idlepc})
@Route.get(
r"/dynamips/images",
status_codes={
200: "List of Dynamips IOS images",
},
description="Retrieve the list of Dynamips IOS images",
output=NODE_LIST_IMAGES_SCHEMA)
async def list_images(request, response):
dynamips_manager = Dynamips.instance()
images = await dynamips_manager.list_images()
response.set_status(200)
response.json(images)
@Route.post(
r"/dynamips/images/{filename:.+}",
parameters={
"filename": "Image filename"
},
status_codes={
204: "Upload a Dynamips IOS image",
},
raw=True,
description="Upload a Dynamips IOS image")
async def upload_image(request, response):
dynamips_manager = Dynamips.instance()
await dynamips_manager.write_image(request.match_info["filename"], request.content)
response.set_status(204)
@Route.get(
r"/dynamips/images/{filename:.+}",
parameters={
"filename": "Image filename"
},
status_codes={
200: "Image returned",
},
raw=True,
description="Download a Dynamips IOS image")
async def download_image(request, response):
filename = request.match_info["filename"]
dynamips_manager = Dynamips.instance()
image_path = dynamips_manager.get_abs_image_path(filename)
# Raise error if user try to escape
if filename[0] == ".":
raise aiohttp.web.HTTPForbidden()
await response.stream_file(image_path)
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate a dynamips instance")
async def duplicate(request, response):
new_node = await Dynamips.instance().duplicate_node(request.match_info["node_id"],
request.json["destination_node_id"])
response.set_status(201)
response.json(new_node)
@Route.get(
r"/projects/{project_id}/dynamips/nodes/{node_id}/console/ws",
description="WebSocket for console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
})
async def console_ws(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
return await vm.start_websocket_console(request)
@Route.post(
r"/projects/{project_id}/dynamips/nodes/{node_id}/console/reset",
description="Reset console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Console has been reset",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Container not started"
})
async def reset_console(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reset_console()
response.set_status(204)
@@ -1,314 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from gns3server.web.route import Route
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
from gns3server.schemas.nio import NIO_SCHEMA
from gns3server.compute.dynamips import Dynamips
from gns3server.schemas.ethernet_hub import (
ETHERNET_HUB_CREATE_SCHEMA,
ETHERNET_HUB_UPDATE_SCHEMA,
ETHERNET_HUB_OBJECT_SCHEMA
)
class EthernetHubHandler:
"""
API entry points for Ethernet hub.
"""
@Route.post(
r"/projects/{project_id}/ethernet_hub/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new Ethernet hub instance",
input=ETHERNET_HUB_CREATE_SCHEMA,
output=ETHERNET_HUB_OBJECT_SCHEMA)
async def create(request, response):
# Use the Dynamips Ethernet hub to simulate this node
dynamips_manager = Dynamips.instance()
node = await dynamips_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
node_type="ethernet_hub",
ports=request.json.get("ports_mapping"))
response.set_status(201)
response.json(node)
@Route.get(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get an Ethernet hub instance",
output=ETHERNET_HUB_OBJECT_SCHEMA)
def show(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(node)
@Route.post(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate an ethernet hub instance")
async def duplicate(request, response):
new_node = await Dynamips.instance().duplicate_node(request.match_info["node_id"],
request.json["destination_node_id"])
response.set_status(201)
response.json(new_node)
@Route.put(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update an Ethernet hub instance",
input=ETHERNET_HUB_UPDATE_SCHEMA,
output=ETHERNET_HUB_OBJECT_SCHEMA)
async def update(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
if "name" in request.json and node.name != request.json["name"]:
await node.set_name(request.json["name"])
if "ports_mapping" in request.json:
node.ports_mapping = request.json["ports_mapping"]
node.updated()
response.json(node)
@Route.delete(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete an Ethernet hub instance")
async def delete(request, response):
dynamips_manager = Dynamips.instance()
await dynamips_manager.delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start an Ethernet hub")
def start(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop an Ethernet hub")
def stop(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend an Ethernet hub (does nothing)")
def suspend(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the hub (always 0)",
"port_number": "Port on the hub"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to an Ethernet hub instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
nio = await dynamips_manager.create_nio(node, request.json)
port_number = int(request.match_info["port_number"])
await node.add_nio(nio, port_number)
response.set_status(201)
response.json(nio)
@Route.delete(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the hub (always 0)",
"port_number": "Port on the hub"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from an Ethernet hub instance")
async def delete_nio(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = await node.remove_nio(port_number)
await nio.delete()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the hub (always 0)",
"port_number": "Port on the hub"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a packet capture on an Ethernet hub instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(node.project.capture_working_directory(), request.json["capture_file_name"])
await node.start_capture(port_number, pcap_file_path, request.json["data_link_type"])
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the hub (always 0)",
"port_number": "Port on the hub"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a packet capture on an Ethernet hub instance")
async def stop_capture(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await node.stop_capture(port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/ethernet_hub/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture (always 0)",
"port_number": "Port on the hub"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = node.get_nio(port_number)
await dynamips_manager.stream_pcap_file(nio, node.project.id, request, response)
@@ -1,341 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from gns3server.web.route import Route
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
from gns3server.schemas.nio import NIO_SCHEMA
from gns3server.compute.dynamips import Dynamips
from gns3server.schemas.ethernet_switch import (
ETHERNET_SWITCH_CREATE_SCHEMA,
ETHERNET_SWITCH_UPDATE_SCHEMA,
ETHERNET_SWITCH_OBJECT_SCHEMA
)
class EthernetSwitchHandler:
"""
API entry points for Ethernet switch.
"""
@Route.post(
r"/projects/{project_id}/ethernet_switch/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new Ethernet switch instance",
input=ETHERNET_SWITCH_CREATE_SCHEMA,
output=ETHERNET_SWITCH_OBJECT_SCHEMA)
async def create(request, response):
# Use the Dynamips Ethernet switch to simulate this node
dynamips_manager = Dynamips.instance()
node = await dynamips_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
console=request.json.get("console"),
console_type=request.json.get("console_type"),
node_type="ethernet_switch",
ports=request.json.get("ports_mapping"))
# On Linux, use the generic switch
# builtin_manager = Builtin.instance()
# node = await builtin_manager.create_node(request.json.pop("name"),
# request.match_info["project_id"],
# request.json.get("node_id"),
# node_type="ethernet_switch")
response.set_status(201)
response.json(node)
@Route.get(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get an Ethernet switch instance",
output=ETHERNET_SWITCH_OBJECT_SCHEMA)
def show(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
# builtin_manager = Builtin.instance()
# node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(node)
@Route.post(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate an ethernet switch instance")
async def duplicate(request, response):
new_node = await Dynamips.instance().duplicate_node(request.match_info["node_id"],
request.json["destination_node_id"])
response.set_status(201)
response.json(new_node)
@Route.put(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update an Ethernet switch instance",
input=ETHERNET_SWITCH_UPDATE_SCHEMA,
output=ETHERNET_SWITCH_OBJECT_SCHEMA)
async def update(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
if "name" in request.json and node.name != request.json["name"]:
await node.set_name(request.json["name"])
if "ports_mapping" in request.json:
node.ports_mapping = request.json["ports_mapping"]
await node.update_port_settings()
if "console_type" in request.json:
node.console_type = request.json["console_type"]
# builtin_manager = Builtin.instance()
# node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
node.updated()
response.json(node)
@Route.delete(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete an Ethernet switch instance")
async def delete(request, response):
dynamips_manager = Dynamips.instance()
await dynamips_manager.delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start an Ethernet switch")
def start(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop an Ethernet switch")
def stop(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend an Ethernet switch (does nothing)")
def suspend(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to an Ethernet switch instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
nio = await dynamips_manager.create_nio(node, request.json)
port_number = int(request.match_info["port_number"])
await node.add_nio(nio, port_number)
#builtin_manager = Builtin.instance()
#node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
#nio = await builtin_manager.create_nio(request.json["nio"])
response.set_status(201)
response.json(nio)
@Route.delete(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from an Ethernet switch instance")
async def delete_nio(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
#builtin_manager = Builtin.instance()
#node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = await node.remove_nio(port_number)
await nio.delete()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a packet capture on an Ethernet switch instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
#builtin_manager = Builtin.instance()
#node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(node.project.capture_working_directory(), request.json["capture_file_name"])
await node.start_capture(port_number, pcap_file_path, request.json["data_link_type"])
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a packet capture on an Ethernet switch instance")
async def stop_capture(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
#builtin_manager = Builtin.instance()
#node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await node.stop_capture(port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/ethernet_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture (always 0)",
"port_number": "Port on the switch"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = node.get_nio(port_number)
await dynamips_manager.stream_pcap_file(nio, node.project.id, request, response)
@@ -1,312 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from gns3server.web.route import Route
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
from gns3server.schemas.nio import NIO_SCHEMA
from gns3server.compute.dynamips import Dynamips
from gns3server.schemas.frame_relay_switch import (
FRAME_RELAY_SWITCH_CREATE_SCHEMA,
FRAME_RELAY_SWITCH_OBJECT_SCHEMA,
FRAME_RELAY_SWITCH_UPDATE_SCHEMA
)
class FrameRelaySwitchHandler:
"""
API entry points for Frame Relay switch.
"""
@Route.post(
r"/projects/{project_id}/frame_relay_switch/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new Frame Relay switch instance",
input=FRAME_RELAY_SWITCH_CREATE_SCHEMA,
output=FRAME_RELAY_SWITCH_OBJECT_SCHEMA)
async def create(request, response):
# Use the Dynamips Frame Relay switch to simulate this node
dynamips_manager = Dynamips.instance()
node = await dynamips_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
node_type="frame_relay_switch",
mappings=request.json.get("mappings"))
response.set_status(201)
response.json(node)
@Route.get(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a Frame Relay switch instance",
output=FRAME_RELAY_SWITCH_OBJECT_SCHEMA)
def show(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(node)
@Route.post(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate a frame relay switch instance")
async def duplicate(request, response):
new_node = await Dynamips.instance().duplicate_node(
request.match_info["node_id"],
request.json["destination_node_id"]
)
response.set_status(201)
response.json(new_node)
@Route.put(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a Frame Relay switch instance",
input=FRAME_RELAY_SWITCH_UPDATE_SCHEMA,
output=FRAME_RELAY_SWITCH_OBJECT_SCHEMA)
async def update(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
if "name" in request.json and node.name != request.json["name"]:
await node.set_name(request.json["name"])
if "mappings" in request.json:
node.mappings = request.json["mappings"]
node.updated()
response.json(node)
@Route.delete(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a Frame Relay switch instance")
async def delete(request, response):
dynamips_manager = Dynamips.instance()
await dynamips_manager.delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a Frame Relay switch")
def start(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a Frame Relay switch")
def stop(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a Frame Relay switch (does nothing)")
def suspend(request, response):
Dynamips.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a Frame Relay switch instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
nio = await dynamips_manager.create_nio(node, request.json)
port_number = int(request.match_info["port_number"])
await node.add_nio(nio, port_number)
response.set_status(201)
response.json(nio)
@Route.delete(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a Frame Relay switch instance")
async def delete_nio(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = await node.remove_nio(port_number)
await nio.delete()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a packet capture on a Frame Relay switch instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(node.project.capture_working_directory(), request.json["capture_file_name"])
await node.start_capture(port_number, pcap_file_path, request.json["data_link_type"])
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the switch (always 0)",
"port_number": "Port on the switch"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a packet capture on a Frame Relay switch instance")
async def stop_capture(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await node.stop_capture(port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/frame_relay_switch/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture (always 0)",
"port_number": "Port on the switch"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
dynamips_manager = Dynamips.instance()
node = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = node.get_nio(port_number)
await dynamips_manager.stream_pcap_file(nio, node.project.id, request, response)
@@ -1,488 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import aiohttp.web
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_OBJECT_SCHEMA
)
class IOUHandler:
"""
API entry points for IOU.
"""
@Route.post(
r"/projects/{project_id}/iou/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new IOU instance",
input=IOU_CREATE_SCHEMA,
output=IOU_OBJECT_SCHEMA)
async def create(request, response):
iou = IOU.instance()
vm = await iou.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
application_id=request.json.get("application_id"),
path=request.json.get("path"),
console=request.json.get("console"),
console_type=request.json.get("console_type", "telnet"))
for name, value in request.json.items():
if hasattr(vm, name) and getattr(vm, name) != value:
if name == "application_id":
continue # we must ignore this to avoid overwriting the application_id allocated by the controller
if name == "startup_config_content" and (vm.startup_config_content and len(vm.startup_config_content) > 0):
continue
if name == "private_config_content" and (vm.private_config_content and len(vm.private_config_content) > 0):
continue
if request.json.get("use_default_iou_values") and (name == "ram" or name == "nvram"):
continue
setattr(vm, name, value)
response.set_status(201)
response.json(vm)
@Route.get(
r"/projects/{project_id}/iou/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get an IOU instance",
output=IOU_OBJECT_SCHEMA)
def show(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(vm)
@Route.put(
r"/projects/{project_id}/iou/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update an IOU instance",
input=IOU_OBJECT_SCHEMA,
output=IOU_OBJECT_SCHEMA)
async def update(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
for name, value in request.json.items():
if hasattr(vm, name) and getattr(vm, name) != value:
if name == "application_id":
continue # we must ignore this to avoid overwriting the application_id allocated by the IOU manager
setattr(vm, name, value)
if vm.use_default_iou_values:
# update the default IOU values in case the image or use_default_iou_values have changed
# this is important to have the correct NVRAM amount in order to correctly push the configs to the NVRAM
await vm.update_default_iou_values()
vm.updated()
response.json(vm)
@Route.delete(
r"/projects/{project_id}/iou/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete an IOU instance")
async def delete(request, response):
await IOU.instance().delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/iou/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate a IOU instance")
async def duplicate(request, response):
new_node = await IOU.instance().duplicate_node(
request.match_info["node_id"],
request.json["destination_node_id"]
)
response.set_status(201)
response.json(new_node)
@Route.post(
r"/projects/{project_id}/iou/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=IOU_START_SCHEMA,
output=IOU_OBJECT_SCHEMA,
description="Start an IOU instance")
async def start(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
for name, value in request.json.items():
if hasattr(vm, name) and getattr(vm, name) != value:
setattr(vm, name, value)
await vm.start()
response.json(vm)
@Route.post(
r"/projects/{project_id}/iou/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop an IOU instance")
async def stop(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.stop()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/iou/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend an IOU instance (does nothing)")
def suspend(request, response):
iou_manager = IOU.instance()
iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/iou/nodes/{node_id}/reload",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Instance reloaded",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Reload an IOU instance")
async def reload(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reload()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a IOU instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
iou_manager = IOU.instance()
vm = iou_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", "nio_tap", "nio_ethernet", "nio_generic_ethernet"):
raise aiohttp.web.HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
nio = iou_manager.create_nio(request.json)
await vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), int(request.match_info["port_number"]), nio)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Update a NIO on an IOU instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def update_nio(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
nio = vm.get_nio(adapter_number, port_number)
if "filters" in request.json:
nio.filters = request.json["filters"]
await vm.adapter_update_nio_binding(adapter_number, port_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a IOU instance")
async def delete_nio(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.adapter_remove_nio_binding(int(request.match_info["adapter_number"]), int(request.match_info["port_number"]))
response.set_status(204)
@Route.post(
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to start a packet capture",
"port_number": "Port on the adapter"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist",
409: "VM not started"
},
description="Start a packet capture on an IOU VM instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(vm.project.capture_working_directory(), request.json["capture_file_name"])
await vm.start_capture(adapter_number, port_number, pcap_file_path, request.json["data_link_type"])
response.json({"pcap_file_path": str(pcap_file_path)})
@Route.post(
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to stop a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist",
409: "VM not started"
},
description="Stop a packet capture on an IOU VM instance")
async def stop_capture(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
await vm.stop_capture(adapter_number, port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
nio = vm.get_nio(adapter_number, port_number)
await iou_manager.stream_pcap_file(nio, vm.project.id, request, response)
@Route.get(
r"/iou/images",
status_codes={
200: "List of IOU images",
},
description="Retrieve the list of IOU images",
output=NODE_LIST_IMAGES_SCHEMA)
async def list_iou_images(request, response):
iou_manager = IOU.instance()
images = await iou_manager.list_images()
response.set_status(200)
response.json(images)
@Route.post(
r"/iou/images/{filename:.+}",
parameters={
"filename": "Image filename"
},
status_codes={
204: "Image uploaded",
},
raw=True,
description="Upload an IOU image")
async def upload_image(request, response):
iou_manager = IOU.instance()
await iou_manager.write_image(request.match_info["filename"], request.content)
response.set_status(204)
@Route.get(
r"/iou/images/{filename:.+}",
parameters={
"filename": "Image filename"
},
status_codes={
200: "Image returned",
},
raw=True,
description="Download an IOU image")
async def download_image(request, response):
filename = request.match_info["filename"]
iou_manager = IOU.instance()
image_path = iou_manager.get_abs_image_path(filename)
# Raise error if user try to escape
if filename[0] == ".":
raise aiohttp.web.HTTPForbidden()
await response.stream_file(image_path)
@Route.get(
r"/projects/{project_id}/iou/nodes/{node_id}/console/ws",
description="WebSocket for console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
})
async def console_ws(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
return await vm.start_websocket_console(request)
@Route.post(
r"/projects/{project_id}/iou/nodes/{node_id}/console/reset",
description="Reset console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Console has been reset",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Container not started"
})
async def reset_console(request, response):
iou_manager = IOU.instance()
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reset_console()
response.set_status(204)
@@ -1,318 +0,0 @@
# -*- coding: utf-8 -*-
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from gns3server.web.route import Route
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
from gns3server.schemas.nio import NIO_SCHEMA
from gns3server.compute.builtin import Builtin
from aiohttp.web import HTTPConflict
from gns3server.schemas.nat import (
NAT_CREATE_SCHEMA,
NAT_OBJECT_SCHEMA,
NAT_UPDATE_SCHEMA
)
class NatHandler:
"""
API entry points for nat
"""
@Route.post(
r"/projects/{project_id}/nat/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new nat instance",
input=NAT_CREATE_SCHEMA,
output=NAT_OBJECT_SCHEMA)
async def create(request, response):
builtin_manager = Builtin.instance()
node = await builtin_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
node_type="nat",
ports=request.json.get("ports_mapping"))
response.set_status(201)
response.json(node)
@Route.get(
r"/projects/{project_id}/nat/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a nat instance",
output=NAT_OBJECT_SCHEMA)
def show(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(node)
@Route.put(
r"/projects/{project_id}/nat/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a nat instance",
input=NAT_UPDATE_SCHEMA,
output=NAT_OBJECT_SCHEMA)
def update(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
for name, value in request.json.items():
if hasattr(node, name) and getattr(node, name) != value:
setattr(node, name, value)
node.updated()
response.json(node)
@Route.delete(
r"/projects/{project_id}/nat/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a nat instance")
async def delete(request, response):
builtin_manager = Builtin.instance()
await builtin_manager.delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/nat/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a nat")
def start(request, response):
Builtin.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/nat/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a nat")
def stop(request, response):
Builtin.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/nat/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a nat (does nothing)")
def suspend(request, response):
Builtin.instance().get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the nat (always 0)",
"port_number": "Port on the nat"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a nat instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
nio = builtin_manager.create_nio(request.json)
port_number = int(request.match_info["port_number"])
await node.add_nio(nio, port_number)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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 updated"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO on a NAT instance")
async def update_nio(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = node.get_nio(port_number)
if "filters" in request.json:
nio.filters = request.json["filters"]
await node.update_nio(port_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the nat (always 0)",
"port_number": "Port on the nat"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a nat instance")
async def delete_nio(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await node.remove_nio(port_number)
response.set_status(204)
@Route.post(
r"/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the nat (always 0)",
"port_number": "Port on the nat"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a packet capture on a nat instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(node.project.capture_working_directory(), request.json["capture_file_name"])
await node.start_capture(port_number, pcap_file_path, request.json["data_link_type"])
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter on the nat (always 0)",
"port_number": "Port on the nat"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a packet capture on a nat instance")
async def stop_capture(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await node.stop_capture(port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture (always 0)",
"port_number": "Port on the nat"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
builtin_manager = Builtin.instance()
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = node.get_nio(port_number)
await builtin_manager.stream_pcap_file(nio, node.project.id, request, response)
@@ -1,59 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from 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:
@Route.post(
r"/projects/{project_id}/ports/udp",
parameters={
"project_id": "Project UUID",
},
status_codes={
201: "UDP port allocated",
404: "The project doesn't exist"
},
description="Allocate an UDP port on the server")
def allocate_udp_port(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
m = PortManager.instance()
udp_port = m.get_free_udp_port(project)
response.set_status(201)
response.json({"udp_port": udp_port})
@Route.get(
r"/network/interfaces",
description="List all the network interfaces available on the server")
def network_interfaces(request, response):
network_interfaces = interfaces()
response.json(network_interfaces)
@Route.get(
r"/network/ports",
description="List all the ports used by the server")
def network_ports(request, response):
m = PortManager.instance()
response.json(m)
@@ -1,64 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import asyncio
import aiohttp
from aiohttp.web import WebSocketResponse
from gns3server.web.route import Route
from gns3server.compute.notification_manager import NotificationManager
import logging
log = logging.getLogger(__name__)
async def process_websocket(ws):
"""
Process ping / pong and close message
"""
try:
await ws.receive()
except aiohttp.WSServerHandshakeError:
pass
class NotificationHandler:
@Route.get(
r"/notifications/ws",
description="Send notifications using Websockets")
async def notifications(request, response):
notifications = NotificationManager.instance()
ws = WebSocketResponse()
await ws.prepare(request)
request.app['websockets'].add(ws)
asyncio.ensure_future(process_websocket(ws))
log.info("New client has connected to compute WebSocket")
try:
with notifications.queue() as queue:
while True:
notification = await queue.get_json(1)
if ws.closed:
break
await ws.send_str(notification)
finally:
log.info("Client has disconnected from compute WebSocket")
if not ws.closed:
await ws.close()
request.app['websockets'].discard(ws)
return ws
@@ -1,302 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import aiohttp
import asyncio
import json
import os
import psutil
from gns3server.web.route import Route
from gns3server.compute.project_manager import ProjectManager
from gns3server.compute import MODULES
from gns3server.utils.cpu_percent import CpuPercent
from gns3server.utils.path import get_default_project_directory
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()
CHUNK_SIZE = 1024 * 8 # 8KB
class ProjectHandler:
# How many clients have subscribed to notifications
_notifications_listening = {}
@Route.get(
r"/projects",
description="List all projects opened on the server",
status_codes={
200: "Project list",
},
output=PROJECT_LIST_SCHEMA
)
def list_projects(request, response):
pm = ProjectManager.instance()
response.set_status(200)
response.json(list(pm.projects))
@Route.post(
r"/projects",
description="Create a new project on the server",
status_codes={
201: "Project created",
403: "Forbidden to create a project",
409: "Project already created"
},
output=PROJECT_OBJECT_SCHEMA,
input=PROJECT_CREATE_SCHEMA)
def create_project(request, response):
pm = ProjectManager.instance()
p = pm.create_project(
name=request.json.get("name"),
path=request.json.get("path"),
project_id=request.json.get("project_id"),
variables=request.json.get("variables", None)
)
response.set_status(201)
response.json(p)
@Route.put(
r"/projects/{project_id}",
description="Update the project on the server",
status_codes={
201: "Project updated",
403: "Forbidden to update a project"
},
output=PROJECT_OBJECT_SCHEMA,
input=PROJECT_UPDATE_SCHEMA)
async def update_project(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
await project.update(
variables=request.json.get("variables", None)
)
response.set_status(200)
response.json(project)
@Route.get(
r"/projects/{project_id}",
description="Get project information",
parameters={
"project_id": "Project UUID",
},
status_codes={
200: "Success",
404: "The project doesn't exist"
},
output=PROJECT_OBJECT_SCHEMA)
def show(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
response.json(project)
@Route.post(
r"/projects/{project_id}/close",
description="Close a project",
parameters={
"project_id": "Project UUID",
},
status_codes={
204: "Project closed",
404: "The project doesn't exist"
})
async def close(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
if ProjectHandler._notifications_listening.setdefault(project.id, 0) <= 1:
await project.close()
pm.remove_project(project.id)
try:
del ProjectHandler._notifications_listening[project.id]
except KeyError:
pass
else:
log.warning("Skip project closing, another client is listening for project notifications")
response.set_status(204)
@Route.delete(
r"/projects/{project_id}",
description="Delete a project from disk",
parameters={
"project_id": "Project UUID",
},
status_codes={
204: "Changes have been written on disk",
404: "The project doesn't exist"
})
async def delete(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
await project.delete()
pm.remove_project(project.id)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/notifications",
description="Receive notifications about the project",
parameters={
"project_id": "Project UUID",
},
status_codes={
200: "End of stream",
404: "The project doesn't exist"
})
async def notification(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
response.content_type = "application/json"
response.set_status(200)
response.enable_chunked_encoding()
response.start(request)
queue = project.get_listen_queue()
ProjectHandler._notifications_listening.setdefault(project.id, 0)
ProjectHandler._notifications_listening[project.id] += 1
await response.write("{}\n".format(json.dumps(ProjectHandler._getPingMessage())).encode("utf-8"))
while True:
try:
(action, msg) = await asyncio.wait_for(queue.get(), 5)
if hasattr(msg, "__json__"):
msg = json.dumps({"action": action, "event": msg.__json__()}, sort_keys=True)
else:
msg = json.dumps({"action": action, "event": msg}, sort_keys=True)
log.debug("Send notification: %s", msg)
await response.write(("{}\n".format(msg)).encode("utf-8"))
except asyncio.TimeoutError:
await response.write("{}\n".format(json.dumps(ProjectHandler._getPingMessage())).encode("utf-8"))
project.stop_listen_queue(queue)
if project.id in ProjectHandler._notifications_listening:
ProjectHandler._notifications_listening[project.id] -= 1
def _getPingMessage(cls):
"""
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
stats["cpu_usage_percent"] = CpuPercent.get(interval=None)
stats["memory_usage_percent"] = psutil.virtual_memory().percent
stats["disk_usage_percent"] = psutil.disk_usage(get_default_project_directory()).percent
return {"action": "ping", "event": stats}
@Route.get(
r"/projects/{project_id}/files",
description="List files of a project",
parameters={
"project_id": "Project UUID",
},
status_codes={
200: "Return a list of files",
404: "The project doesn't exist"
},
output=PROJECT_FILE_LIST_SCHEMA)
async def list_files(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
files = await project.list_files()
response.json(files)
response.set_status(200)
@Route.get(
r"/projects/{project_id}/files/{path:.+}",
description="Get a file from a project",
parameters={
"project_id": "Project UUID",
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def get_file(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
path = request.match_info["path"]
path = os.path.normpath(path)
# Raise error if user try to escape
if path[0] == ".":
raise aiohttp.web.HTTPForbidden()
path = os.path.join(project.path, path)
await response.stream_file(path)
@Route.post(
r"/projects/{project_id}/files/{path:.+}",
description="Write a file to a project",
parameters={
"project_id": "Project UUID",
},
raw=True,
status_codes={
200: "File returned",
403: "Permission denied",
404: "The path doesn't exist"
})
async def write_file(request, response):
pm = ProjectManager.instance()
project = pm.get_project(request.match_info["project_id"])
path = request.match_info["path"]
path = os.path.normpath(path)
# Raise error if user try to escape
if path[0] == ".":
raise aiohttp.web.HTTPForbidden()
path = os.path.join(project.path, path)
response.set_status(200)
try:
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'wb+') as f:
while True:
try:
chunk = await request.content.read(CHUNK_SIZE)
except asyncio.TimeoutError:
raise aiohttp.web.HTTPRequestTimeout(text="Timeout when writing to file '{}'".format(path))
if not chunk:
break
f.write(chunk)
except FileNotFoundError:
raise aiohttp.web.HTTPNotFound()
except PermissionError:
raise aiohttp.web.HTTPForbidden()
@@ -1,617 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os.path
import aiohttp.web
from gns3server.web.route import Route
from gns3server.compute.project_manager import ProjectManager
from gns3server.schemas.nio import NIO_SCHEMA
from gns3server.compute.qemu import Qemu
from gns3server.config import Config
from gns3server.schemas.node import (
NODE_LIST_IMAGES_SCHEMA,
NODE_CAPTURE_SCHEMA
)
from gns3server.schemas.qemu import (
QEMU_CREATE_SCHEMA,
QEMU_UPDATE_SCHEMA,
QEMU_OBJECT_SCHEMA,
QEMU_RESIZE_SCHEMA,
QEMU_BINARY_LIST_SCHEMA,
QEMU_BINARY_FILTER_SCHEMA,
QEMU_CAPABILITY_LIST_SCHEMA,
QEMU_IMAGE_CREATE_SCHEMA,
QEMU_IMAGE_UPDATE_SCHEMA
)
class QEMUHandler:
"""
API entry points for QEMU.
"""
@Route.post(
r"/projects/{project_id}/qemu/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new Qemu VM instance",
input=QEMU_CREATE_SCHEMA,
output=QEMU_OBJECT_SCHEMA)
async def create(request, response):
qemu = Qemu.instance()
vm = await qemu.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.pop("node_id", None),
linked_clone=request.json.get("linked_clone", True),
qemu_path=request.json.pop("qemu_path", None),
console=request.json.pop("console", None),
console_type=request.json.pop("console_type", "telnet"),
aux=request.json.get("aux"),
aux_type=request.json.pop("aux_type", "none"),
platform=request.json.pop("platform", None))
for name, value in request.json.items():
if hasattr(vm, name) and getattr(vm, name) != value:
setattr(vm, name, value)
response.set_status(201)
response.json(vm)
@Route.get(
r"/projects/{project_id}/qemu/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a Qemu VM instance",
output=QEMU_OBJECT_SCHEMA)
def show(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(vm)
@Route.put(
r"/projects/{project_id}/qemu/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a Qemu VM instance",
input=QEMU_UPDATE_SCHEMA,
output=QEMU_OBJECT_SCHEMA)
async def update(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
# update the console first to avoid issue if updating console type
vm.console = request.json.pop("console", vm.console)
for name, value in request.json.items():
if hasattr(vm, name) and getattr(vm, name) != value:
setattr(vm, name, value)
if name == "cdrom_image":
# let the guest know about the new cdrom image
await vm.update_cdrom_image()
vm.updated()
response.json(vm)
@Route.delete(
r"/projects/{project_id}/qemu/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a Qemu VM instance")
async def delete(request, response):
await Qemu.instance().delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate a Qemu instance")
async def duplicate(request, response):
new_node = await Qemu.instance().duplicate_node(
request.match_info["node_id"],
request.json["destination_node_id"]
)
response.set_status(201)
response.json(new_node)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/resize_disk",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance updated",
404: "Instance doesn't exist"
},
description="Resize a Qemu VM disk image",
input=QEMU_RESIZE_SCHEMA)
async def resize_disk(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.resize_disk(request.json["drive_name"], request.json["extend"])
response.set_status(201)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a Qemu VM instance",
output=QEMU_OBJECT_SCHEMA)
async def start(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
hardware_accel = qemu_manager.config.get_section_config("Qemu").getboolean("enable_hardware_acceleration", True)
if sys.platform.startswith("linux"):
# the enable_kvm option was used before version 2.0 and has priority
enable_kvm = qemu_manager.config.get_section_config("Qemu").getboolean("enable_kvm")
if enable_kvm is not None:
hardware_accel = enable_kvm
if hardware_accel and "-no-kvm" not in vm.options and "-no-hax" not in vm.options:
pm = ProjectManager.instance()
if pm.check_hardware_virtualization(vm) is False:
raise aiohttp.web.HTTPConflict(text="Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
await vm.start()
response.json(vm)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a Qemu VM instance")
async def stop(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.stop()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/reload",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Instance reloaded",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Reload a Qemu VM instance")
async def reload(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reload()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a Qemu VM instance")
async def suspend(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.suspend()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/resume",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Instance resumed",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Resume a Qemu VM instance")
async def resume(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.resume()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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)"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a Qemu VM instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
qemu_manager = Qemu.instance()
vm = qemu_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"):
raise aiohttp.web.HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
nio = qemu_manager.create_nio(request.json)
await vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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 updated"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO on a Qemu instance")
async def update_nio(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
nio = vm.get_nio(adapter_number)
if "filters" in request.json:
nio.filters = request.json["filters"]
if "suspend" in request.json:
nio.suspend = request.json["suspend"]
await vm.adapter_update_nio_binding(adapter_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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)"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a Qemu VM instance")
async def delete_nio(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
await vm.adapter_remove_nio_binding(adapter_number)
response.set_status(204)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to start a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist",
},
description="Start a packet capture on a Qemu VM instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
qemu_manager = Qemu.instance()
vm = qemu_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"])
await vm.start_capture(adapter_number, pcap_file_path)
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to stop a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist",
},
description="Stop a packet capture on a Qemu VM instance")
async def stop_capture(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
await vm.stop_capture(adapter_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
nio = vm.get_nio(adapter_number)
await qemu_manager.stream_pcap_file(nio, vm.project.id, request, response)
@Route.get(
r"/qemu/binaries",
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a list of available Qemu binaries",
input=QEMU_BINARY_FILTER_SCHEMA,
output=QEMU_BINARY_LIST_SCHEMA)
async def list_binaries(request, response):
binaries = await Qemu.binary_list(request.json.get("archs", None))
response.json(binaries)
@Route.get(
r"/qemu/img-binaries",
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a list of available Qemu-img binaries",
output=QEMU_BINARY_LIST_SCHEMA)
async def list_img_binaries(request, response):
binaries = await Qemu.img_binary_list()
response.json(binaries)
@Route.get(
r"/qemu/capabilities",
status_codes={
200: "Success"
},
description="Get a list of Qemu capabilities on this server",
output=QEMU_CAPABILITY_LIST_SCHEMA
)
async def get_capabilities(request, response):
capabilities = {"kvm": []}
kvms = await Qemu.get_kvm_archs()
if kvms:
capabilities["kvm"] = kvms
response.json(capabilities)
@Route.post(
r"/qemu/img",
status_codes={
201: "Image created",
},
description="Create a Qemu image",
input=QEMU_IMAGE_CREATE_SCHEMA
)
async def create_img(request, response):
qemu_img = request.json.pop("qemu_img")
path = request.json.pop("path")
if os.path.isabs(path):
config = Config.instance()
if config.get_section_config("Server").getboolean("local", False) is False:
response.set_status(403)
return
await Qemu.instance().create_disk(qemu_img, path, request.json)
response.set_status(201)
@Route.put(
r"/qemu/img",
status_codes={
201: "Image Updated",
},
description="Update a Qemu image",
input=QEMU_IMAGE_UPDATE_SCHEMA
)
async def update_img(request, response):
qemu_img = request.json.pop("qemu_img")
path = request.json.pop("path")
if os.path.isabs(path):
config = Config.instance()
if config.get_section_config("Server").getboolean("local", False) is False:
response.set_status(403)
return
if "extend" in request.json:
await Qemu.instance().resize_disk(qemu_img, path, request.json.pop("extend"))
response.set_status(201)
@Route.get(
r"/qemu/images",
status_codes={
200: "List of Qemu images",
},
description="Retrieve the list of Qemu images",
output=NODE_LIST_IMAGES_SCHEMA)
async def list_qemu_images(request, response):
qemu_manager = Qemu.instance()
images = await qemu_manager.list_images()
response.set_status(200)
response.json(images)
@Route.post(
r"/qemu/images/{filename:.+}",
parameters={
"filename": "Image filename"
},
status_codes={
204: "Image uploaded",
},
raw=True,
description="Upload Qemu image")
async def upload_image(request, response):
qemu_manager = Qemu.instance()
await qemu_manager.write_image(request.match_info["filename"], request.content)
response.set_status(204)
@Route.get(
r"/qemu/images/{filename:.+}",
parameters={
"filename": "Image filename"
},
status_codes={
200: "Image returned",
},
raw=True,
description="Download Qemu image")
async def download_image(request, response):
filename = request.match_info["filename"]
qemu_manager = Qemu.instance()
image_path = qemu_manager.get_abs_image_path(filename)
# Raise error if user try to escape
if filename[0] == ".":
raise aiohttp.web.HTTPForbidden()
await response.stream_file(image_path)
@Route.get(
r"/projects/{project_id}/qemu/nodes/{node_id}/console/ws",
description="WebSocket for console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
})
async def console_ws(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
return await vm.start_websocket_console(request)
@Route.post(
r"/projects/{project_id}/qemu/nodes/{node_id}/console/reset",
description="Reset console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Console has been reset",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Container not started"
})
async def reset_console(request, response):
qemu_manager = Qemu.instance()
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reset_console()
response.set_status(204)
@@ -1,135 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import psutil
import platform
from gns3server.web.route import Route
from gns3server.config import Config
from gns3server.schemas.version import VERSION_SCHEMA
from gns3server.schemas.server_statistics import SERVER_STATISTICS_SCHEMA
from gns3server.compute.port_manager import PortManager
from gns3server.utils.cpu_percent import CpuPercent
from gns3server.version import __version__
from gns3server.utils.path import get_default_project_directory
from aiohttp.web import HTTPConflict
class ServerHandler:
@Route.get(
r"/version",
description="Retrieve the server version number",
output=VERSION_SCHEMA)
def version(request, response):
config = Config.instance()
local_server = config.get_section_config("Server").getboolean("local", False)
response.json({"version": __version__, "local": local_server})
@Route.get(
r"/statistics",
description="Retrieve server statistics",
output=SERVER_STATISTICS_SCHEMA,
status_codes={
200: "Statistics information returned",
409: "Conflict"
})
def statistics(request, response):
try:
memory_total = psutil.virtual_memory().total
memory_free = psutil.virtual_memory().available
memory_used = memory_total - memory_free # actual memory usage in a cross platform fashion
swap_total = psutil.swap_memory().total
swap_free = psutil.swap_memory().free
swap_used = psutil.swap_memory().used
cpu_percent = int(CpuPercent.get())
load_average_percent = [int(x / psutil.cpu_count() * 100) for x in psutil.getloadavg()]
memory_percent = int(psutil.virtual_memory().percent)
swap_percent = int(psutil.swap_memory().percent)
disk_usage_percent = int(psutil.disk_usage(get_default_project_directory()).percent)
except psutil.Error as e:
raise HTTPConflict(text="Psutil error detected: {}".format(e))
response.json({"memory_total": memory_total,
"memory_free": memory_free,
"memory_used": memory_used,
"swap_total": swap_total,
"swap_free": swap_free,
"swap_used": swap_used,
"cpu_usage_percent": cpu_percent,
"memory_usage_percent": memory_percent,
"swap_usage_percent": swap_percent,
"disk_usage_percent": disk_usage_percent,
"load_average_percent": load_average_percent})
@Route.get(
r"/debug",
description="Return debug information about the compute",
status_codes={
201: "Written"
})
def debug(request, response):
response.content_type = "text/plain"
response.text = ServerHandler._getDebugData()
@staticmethod
def _getDebugData():
try:
addrs = ["* {}: {}".format(key, val) for key, val in psutil.net_if_addrs().items()]
except UnicodeDecodeError:
addrs = ["INVALID ADDR WITH UNICODE CHARACTERS"]
data = """Version: {version}
OS: {os}
Python: {python}
CPU: {cpu}
Memory: {memory}
Networks:
{addrs}
""".format(
version=__version__,
os=platform.platform(),
python=platform.python_version(),
memory=psutil.virtual_memory(),
cpu=psutil.cpu_times(),
addrs="\n".join(addrs)
)
try:
connections = psutil.net_connections()
# You need to be root for OSX
except psutil.AccessDenied:
connections = None
if connections:
data += "\n\nConnections:\n"
for port in PortManager.instance().tcp_ports:
found = False
for open_port in connections:
if open_port.laddr[1] == port:
found = True
data += "TCP {}: {}\n".format(port, found)
for port in PortManager.instance().udp_ports:
found = False
for open_port in connections:
if open_port.laddr[1] == port:
found = True
data += "UDP {}: {}\n".format(port, found)
return data
@@ -1,365 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from aiohttp.web import HTTPConflict
from gns3server.web.route import Route
from gns3server.schemas.nio import NIO_SCHEMA
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
from gns3server.compute.traceng import TraceNG
from gns3server.schemas.traceng import (
TRACENG_CREATE_SCHEMA,
TRACENG_UPDATE_SCHEMA,
TRACENG_START_SCHEMA,
TRACENG_OBJECT_SCHEMA
)
class TraceNGHandler:
"""
API entry points for TraceNG.
"""
@Route.post(
r"/projects/{project_id}/traceng/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new TraceNG instance",
input=TRACENG_CREATE_SCHEMA,
output=TRACENG_OBJECT_SCHEMA)
async def create(request, response):
traceng = TraceNG.instance()
vm = await traceng.create_node(request.json["name"],
request.match_info["project_id"],
request.json.get("node_id"),
console=request.json.get("console"))
vm.ip_address = request.json.get("ip_address", "")
vm.default_destination = request.json.get("default_destination", "")
response.set_status(201)
response.json(vm)
@Route.get(
r"/projects/{project_id}/traceng/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a TraceNG instance",
output=TRACENG_OBJECT_SCHEMA)
def show(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(vm)
@Route.put(
r"/projects/{project_id}/traceng/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a TraceNG instance",
input=TRACENG_UPDATE_SCHEMA,
output=TRACENG_OBJECT_SCHEMA)
def update(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
vm.name = request.json.get("name", vm.name)
vm.ip_address = request.json.get("ip_address", vm.ip_address)
vm.default_destination = request.json.get("default_destination", vm.default_destination)
vm.updated()
response.json(vm)
@Route.delete(
r"/projects/{project_id}/traceng/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a TraceNG instance")
async def delete(request, response):
await TraceNG.instance().delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/traceng/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate a TraceNG instance")
async def duplicate(request, response):
new_node = await TraceNG.instance().duplicate_node(
request.match_info["node_id"],
request.json["destination_node_id"]
)
response.set_status(201)
response.json(new_node)
@Route.post(
r"/projects/{project_id}/traceng/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a TraceNG instance",
input=TRACENG_START_SCHEMA,
output=TRACENG_OBJECT_SCHEMA)
async def start(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.start(request.get("destination"))
response.json(vm)
@Route.post(
r"/projects/{project_id}/traceng/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a TraceNG instance")
async def stop(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.stop()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/traceng/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a TraceNG instance (does nothing)")
def suspend(request, response):
traceng_manager = TraceNG.instance()
traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/traceng/nodes/{node_id}/reload",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Instance reloaded",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Reload a TraceNG instance")
async def reload(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reload()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/traceng/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a TraceNG instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_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"):
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
nio = traceng_manager.create_nio(request.json)
await vm.port_add_nio_binding(int(request.match_info["port_number"]), nio)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/traceng/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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 updated"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO on a TraceNG instance")
async def update_nio(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = vm.get_nio(port_number)
if "filters" in request.json:
nio.filters = request.json["filters"]
await vm.port_update_nio_binding(port_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/traceng/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a TraceNG instance")
async def delete_nio(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await vm.port_remove_nio_binding(port_number)
response.set_status(204)
@Route.post(
r"/projects/{project_id}/traceng/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to start a packet capture",
"port_number": "Port on the adapter"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist",
},
description="Start a packet capture on a TraceNG instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(vm.project.capture_working_directory(), request.json["capture_file_name"])
await vm.start_capture(port_number, pcap_file_path)
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/traceng/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to stop a packet capture",
"port_number": "Port on the adapter"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist",
},
description="Stop a packet capture on a TraceNG instance")
async def stop_capture(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await vm.stop_capture(port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/traceng/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture",
"port_number": "Port on the adapter"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
traceng_manager = TraceNG.instance()
vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = vm.get_nio(port_number)
await traceng_manager.stream_pcap_file(nio, vm.project.id, request, response)
@@ -1,459 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from aiohttp.web import HTTPConflict
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.virtualbox.virtualbox_error import VirtualBoxError
from gns3server.compute.project_manager import ProjectManager
from gns3server.schemas.virtualbox import (
VBOX_CREATE_SCHEMA,
VBOX_OBJECT_SCHEMA
)
class VirtualBoxHandler:
"""
API entry points for VirtualBox.
"""
@Route.post(
r"/projects/{project_id}/virtualbox/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new VirtualBox VM instance",
input=VBOX_CREATE_SCHEMA,
output=VBOX_OBJECT_SCHEMA)
async def create(request, response):
vbox_manager = VirtualBox.instance()
vm = await vbox_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
request.json.pop("vmname"),
linked_clone=request.json.pop("linked_clone", False),
console=request.json.get("console", None),
console_type=request.json.get("console_type", "telnet"),
adapters=request.json.get("adapters", 0))
if "ram" in request.json:
ram = request.json.pop("ram")
if ram != vm.ram:
await vm.set_ram(ram)
for name, value in request.json.items():
if name != "node_id":
if hasattr(vm, name) and getattr(vm, name) != value:
setattr(vm, name, value)
response.set_status(201)
response.json(vm)
@Route.get(
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a VirtualBox VM instance",
output=VBOX_OBJECT_SCHEMA)
def show(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(vm)
@Route.put(
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a VirtualBox VM instance",
input=VBOX_OBJECT_SCHEMA,
output=VBOX_OBJECT_SCHEMA)
async def update(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
if "name" in request.json:
name = request.json.pop("name")
vmname = request.json.pop("vmname", None)
if name != vm.name:
oldname = vm.name
vm.name = name
if vm.linked_clone:
try:
await vm.set_vmname(vm.name)
except VirtualBoxError as e: # In case of error we rollback (we can't change the name when running)
vm.name = oldname
vm.updated()
raise e
if "adapters" in request.json:
adapters = int(request.json.pop("adapters"))
if adapters != vm.adapters:
await vm.set_adapters(adapters)
if "ram" in request.json:
ram = request.json.pop("ram")
if ram != vm.ram:
await vm.set_ram(ram)
# update the console first to avoid issue if updating console type
vm.console = request.json.pop("console", vm.console)
for name, value in request.json.items():
if hasattr(vm, name) and getattr(vm, name) != value:
setattr(vm, name, value)
vm.updated()
response.json(vm)
@Route.delete(
r"/projects/{project_id}/virtualbox/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a VirtualBox VM instance")
async def delete(request, response):
# check the project_id exists
ProjectManager.instance().get_project(request.match_info["project_id"])
await VirtualBox.instance().delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a VirtualBox VM instance")
async def start(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
if (await vm.check_hw_virtualization()):
pm = ProjectManager.instance()
if pm.check_hardware_virtualization(vm) is False:
raise HTTPConflict(text="Cannot start VM because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or KVM (on Linux)")
await vm.start()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a VirtualBox VM instance")
async def stop(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.stop()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a VirtualBox VM instance")
async def suspend(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.suspend()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/resume",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance resumed",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Resume a suspended VirtualBox VM instance")
async def resume(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.resume()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/reload",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance reloaded",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Reload a VirtualBox VM instance")
async def reload(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reload()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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)"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a VirtualBox VM instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_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", "nio_nat"):
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
nio = vbox_manager.create_nio(request.json)
await vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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 updated"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO on a Virtualbox instance")
async def update_nio(request, response):
virtualbox_manager = VirtualBox.instance()
vm = virtualbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
nio = vm.get_nio(adapter_number)
if "filters" in request.json:
nio.filters = request.json["filters"]
if "suspend" in request.json:
nio.suspend = request.json["suspend"]
await vm.adapter_update_nio_binding(adapter_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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)"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a VirtualBox VM instance")
async def delete_nio(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
await vm.adapter_remove_nio_binding(adapter_number)
response.set_status(204)
@Route.post(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to start a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a packet capture on a VirtualBox VM instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_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"])
await vm.start_capture(adapter_number, pcap_file_path)
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to stop a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a packet capture on a VirtualBox VM instance")
async def stop_capture(request, response):
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
await vm.stop_capture(adapter_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
virtualbox_manager = VirtualBox.instance()
vm = virtualbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
nio = vm.get_nio(adapter_number)
await virtualbox_manager.stream_pcap_file(nio, vm.project.id, request, response)
@Route.get(
r"/virtualbox/vms",
status_codes={
200: "Success",
},
description="Get all available VirtualBox VMs")
async def get_vms(request, response):
vbox_manager = VirtualBox.instance()
vms = await vbox_manager.list_vms()
response.json(vms)
@Route.get(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/console/ws",
description="WebSocket for console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
})
async def console_ws(request, response):
virtualbox_manager = VirtualBox.instance()
vm = virtualbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
return await vm.start_websocket_console(request)
@Route.post(
r"/projects/{project_id}/virtualbox/nodes/{node_id}/console/reset",
description="Reset console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Console has been reset",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Container not started"
})
async def reset_console(request, response):
virtualbox_manager = VirtualBox.instance()
vm = virtualbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reset_console()
response.set_status(204)
@@ -1,444 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from aiohttp.web import HTTPConflict
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_OBJECT_SCHEMA
)
class VMwareHandler:
"""
API entry points for VMware.
"""
@Route.post(
r"/projects/{project_id}/vmware/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new VMware VM instance",
input=VMWARE_CREATE_SCHEMA,
output=VMWARE_OBJECT_SCHEMA)
async def create(request, response):
vmware_manager = VMware.instance()
vm = await vmware_manager.create_node(request.json.pop("name"),
request.match_info["project_id"],
request.json.get("node_id"),
request.json.pop("vmx_path"),
linked_clone=request.json.pop("linked_clone"),
console=request.json.get("console", None),
console_type=request.json.get("console_type", "telnet"))
for name, value in request.json.items():
if name != "node_id":
if hasattr(vm, name) and getattr(vm, name) != value:
setattr(vm, name, value)
response.set_status(201)
response.json(vm)
@Route.get(
r"/projects/{project_id}/vmware/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a VMware VM instance",
output=VMWARE_OBJECT_SCHEMA)
def show(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(vm)
@Route.put(
r"/projects/{project_id}/vmware/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a VMware VM instance",
input=VMWARE_OBJECT_SCHEMA,
output=VMWARE_OBJECT_SCHEMA)
def update(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
# update the console first to avoid issue if updating console type
vm.console = request.json.pop("console", vm.console)
for name, value in request.json.items():
if hasattr(vm, name) and getattr(vm, name) != value:
setattr(vm, name, value)
vm.updated()
response.json(vm)
@Route.delete(
r"/projects/{project_id}/vmware/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a VMware VM instance")
async def delete(request, response):
# check the project_id exists
ProjectManager.instance().get_project(request.match_info["project_id"])
await VMware.instance().delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a VMware VM instance")
async def start(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
if vm.check_hw_virtualization():
pm = ProjectManager.instance()
if pm.check_hardware_virtualization(vm) is False:
raise HTTPConflict(text="Cannot start VM because hardware virtualization (VT-x/AMD-V) is already used by another software like VirtualBox or KVM (on Linux)")
await vm.start()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a VMware VM instance")
async def stop(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.stop()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a VMware VM instance")
async def suspend(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.suspend()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/resume",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance resumed",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Resume a suspended VMware VM instance")
async def resume(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.resume()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/reload",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance reloaded",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Reload a VMware VM instance")
async def reload(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reload()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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)"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a VMware VM instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
vmware_manager = VMware.instance()
vm = vmware_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", "nio_vmnet", "nio_nat", "nio_tap"):
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
nio = vmware_manager.create_nio(request.json)
await vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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 updated"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO on a VMware VM instance")
async def update_nio(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
nio = vm.get_nio(adapter_number)
if "filters" in request.json:
nio.filters = request.json["filters"]
await vm.adapter_update_nio_binding(adapter_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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)"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a VMware VM instance")
async def delete_nio(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
await vm.adapter_remove_nio_binding(adapter_number)
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to start a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist",
},
description="Start a packet capture on a VMware VM instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
vmware_manager = VMware.instance()
vm = vmware_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"])
await vm.start_capture(adapter_number, pcap_file_path)
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to stop a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist",
},
description="Stop a packet capture on a VMware VM instance")
async def stop_capture(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
await vm.stop_capture(adapter_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture",
"port_number": "Port on the adapter (always 0)"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
adapter_number = int(request.match_info["adapter_number"])
nio = vm.get_nio(adapter_number)
await vmware_manager.stream_pcap_file(nio, vm.project.id, request, response)
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/interfaces/vmnet",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
201: "VMnet interface allocated",
},
description="Allocate a VMware VMnet interface on the server")
def allocate_vmnet(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
vmware_manager.refresh_vmnet_list(ubridge=False)
vmnet = vmware_manager.allocate_vmnet()
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")
async def get_vms(request, response):
vmware_manager = VMware.instance()
vms = await vmware_manager.list_vms()
response.json(vms)
@Route.get(
r"/projects/{project_id}/vmware/nodes/{node_id}/console/ws",
description="WebSocket for console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
})
async def console_ws(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
return await vm.start_websocket_console(request)
@Route.post(
r"/projects/{project_id}/vmware/nodes/{node_id}/console/reset",
description="Reset console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Console has been reset",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Container not started"
})
async def reset_console(request, response):
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reset_console()
response.set_status(204)
@@ -1,397 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from aiohttp.web import HTTPConflict
from gns3server.web.route import Route
from gns3server.schemas.nio import NIO_SCHEMA
from gns3server.schemas.node import NODE_CAPTURE_SCHEMA
from gns3server.compute.vpcs import VPCS
from gns3server.schemas.vpcs import (
VPCS_CREATE_SCHEMA,
VPCS_UPDATE_SCHEMA,
VPCS_OBJECT_SCHEMA
)
class VPCSHandler:
"""
API entry points for VPCS.
"""
@Route.post(
r"/projects/{project_id}/vpcs/nodes",
parameters={
"project_id": "Project UUID"
},
status_codes={
201: "Instance created",
400: "Invalid request",
409: "Conflict"
},
description="Create a new VPCS instance",
input=VPCS_CREATE_SCHEMA,
output=VPCS_OBJECT_SCHEMA)
async def create(request, response):
vpcs = VPCS.instance()
vm = await vpcs.create_node(request.json["name"],
request.match_info["project_id"],
request.json.get("node_id"),
console=request.json.get("console"),
console_type=request.json.get("console_type", "telnet"),
startup_script=request.json.get("startup_script"))
response.set_status(201)
response.json(vm)
@Route.get(
r"/projects/{project_id}/vpcs/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Success",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Get a VPCS instance",
output=VPCS_OBJECT_SCHEMA)
def show(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.json(vm)
@Route.put(
r"/projects/{project_id}/vpcs/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
200: "Instance updated",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Conflict"
},
description="Update a VPCS instance",
input=VPCS_UPDATE_SCHEMA,
output=VPCS_OBJECT_SCHEMA)
def update(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_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.console_type = request.json.get("console_type", vm.console_type)
vm.updated()
response.json(vm)
@Route.delete(
r"/projects/{project_id}/vpcs/nodes/{node_id}",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Delete a VPCS instance")
async def delete(request, response):
await VPCS.instance().delete_node(request.match_info["node_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vpcs/nodes/{node_id}/duplicate",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
201: "Instance duplicated",
404: "Instance doesn't exist"
},
description="Duplicate a VPCS instance")
async def duplicate(request, response):
new_node = await VPCS.instance().duplicate_node(
request.match_info["node_id"],
request.json["destination_node_id"]
)
response.set_status(201)
response.json(new_node)
@Route.post(
r"/projects/{project_id}/vpcs/nodes/{node_id}/start",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance started",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Start a VPCS instance",
output=VPCS_OBJECT_SCHEMA)
async def start(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.start()
response.json(vm)
@Route.post(
r"/projects/{project_id}/vpcs/nodes/{node_id}/stop",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance stopped",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Stop a VPCS instance")
async def stop(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.stop()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vpcs/nodes/{node_id}/suspend",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID"
},
status_codes={
204: "Instance suspended",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Suspend a VPCS instance (does nothing)")
def suspend(request, response):
vpcs_manager = VPCS.instance()
vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vpcs/nodes/{node_id}/reload",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Instance reloaded",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Reload a VPCS instance")
async def reload(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reload()
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a VPCS instance",
input=NIO_SCHEMA,
output=NIO_SCHEMA)
async def create_nio(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_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", "nio_tap"):
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
port_number = int(request.match_info["port_number"])
nio = vpcs_manager.create_nio(request.json)
await vm.port_add_nio_binding(port_number, nio)
response.set_status(201)
response.json(nio)
@Route.put(
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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 updated"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO on a VPCS instance")
async def update_nio(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = vm.get_nio(port_number)
if "filters" in request.json:
nio.filters = request.json["filters"]
await vm.port_update_nio_binding(port_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"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"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a VPCS instance")
async def delete_nio(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await vm.port_remove_nio_binding(port_number)
response.set_status(204)
@Route.post(
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to start a packet capture",
"port_number": "Port on the adapter"
},
status_codes={
200: "Capture started",
400: "Invalid request",
404: "Instance doesn't exist",
},
description="Start a packet capture on a VPCS instance",
input=NODE_CAPTURE_SCHEMA)
async def start_capture(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
pcap_file_path = os.path.join(vm.project.capture_working_directory(), request.json["capture_file_name"])
await vm.start_capture(port_number, pcap_file_path)
response.json({"pcap_file_path": pcap_file_path})
@Route.post(
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to stop a packet capture",
"port_number": "Port on the adapter"
},
status_codes={
204: "Capture stopped",
400: "Invalid request",
404: "Instance doesn't exist",
},
description="Stop a packet capture on a VPCS instance")
async def stop_capture(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
await vm.stop_capture(port_number)
response.set_status(204)
@Route.get(
r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/pcap",
description="Stream the pcap capture file",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Adapter to steam a packet capture",
"port_number": "Port on the adapter"
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
async def stream_pcap_file(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
port_number = int(request.match_info["port_number"])
nio = vm.get_nio(port_number)
await vpcs_manager.stream_pcap_file(nio, vm.project.id, request, response)
@Route.get(
r"/projects/{project_id}/vpcs/nodes/{node_id}/console/ws",
description="WebSocket for console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
})
async def console_ws(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
return await vm.start_websocket_console(request)
@Route.post(
r"/projects/{project_id}/vpcs/nodes/{node_id}/console/reset",
description="Reset console",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
},
status_codes={
204: "Console has been reset",
400: "Invalid request",
404: "Instance doesn't exist",
409: "Container not started"
})
async def reset_console(request, response):
vpcs_manager = VPCS.instance()
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
await vm.reset_console()
response.set_status(204)