diff --git a/.github/workflows/publish_api_documentation.yml b/.github/workflows/publish_api_documentation.yml index 9f6fa41e..348ebe16 100644 --- a/.github/workflows/publish_api_documentation.yml +++ b/.github/workflows/publish_api_documentation.yml @@ -15,10 +15,15 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - ref: "3.0" + ref: "gh-pages" - uses: actions/setup-python@v2 with: python-version: 3.6 + - name: Merge changes from 3.0 branch + run: | + git config user.name github-actions + git config user.email github-actions@github.com + git merge origin/3.0 -X theirs - name: Install dependencies run: | python -m pip install --upgrade pip @@ -32,11 +37,7 @@ jobs: python3 publish_api_documentation.py - name: Publish the API documentation run: | - git config user.name github-actions - git config user.email github-actions@github.com git add docs git status git commit -m "Publish API documentation" - git checkout gh-pages - git merge 3.0 -X theirs git push diff --git a/docs/swagger.html b/docs/redoc.html similarity index 100% rename from docs/swagger.html rename to docs/redoc.html diff --git a/gns3server/app.py b/gns3server/app.py index 0cc3d035..bdf41541 100644 --- a/gns3server/app.py +++ b/gns3server/app.py @@ -49,7 +49,7 @@ log = logging.getLogger(__name__) app = FastAPI(title="GNS3 controller API", description="This page describes the public controller API for GNS3", - version="v2") + version="v3") origins = [ "http://127.0.0.1", @@ -71,8 +71,8 @@ app.add_middleware( ) app.include_router(index.router, tags=["Index"]) -app.include_router(controller.router, prefix="/v2") -app.mount("/v2/compute", compute_api) +app.include_router(controller.router, prefix="/v3") +app.mount("/v3/compute", compute_api) @app.exception_handler(ControllerError) diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index 64e5c637..68bd9e75 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -44,11 +44,11 @@ from ..error import NodeError, ImageMissingError from ..nios.nio_udp import NIOUDP from ..nios.nio_tap import NIOTAP from ..base_node import BaseNode -from ...schemas.qemu import QEMU_OBJECT_SCHEMA, QEMU_PLATFORMS from ...utils.asyncio import monitor_process from ...utils.images import md5sum from ...utils import macaddress_to_int, int_to_macaddress +from gns3server.schemas.qemu_nodes import Qemu, QemuPlatform import logging log = logging.getLogger(__name__) @@ -216,7 +216,10 @@ class QemuVM(BaseNode): self._platform = "i386" else: self._platform = re.sub(r'^qemu-system-(.*)$', r'\1', qemu_bin, re.IGNORECASE) - if self._platform.split(".")[0] not in QEMU_PLATFORMS: + + try: + QemuPlatform(self._platform.split(".")[0]) + except ValueError: raise QemuError("Platform {} is unknown".format(self._platform)) log.info('QEMU VM "{name}" [{id}] has set the QEMU path to {qemu_path}'.format(name=self._name, id=self._id, @@ -2288,7 +2291,7 @@ class QemuVM(BaseNode): "node_directory": self.working_path } # Qemu has a long list of options. The JSON schema is the single source of information - for field in QEMU_OBJECT_SCHEMA["required"]: + for field in Qemu.schema()["properties"]: if field not in answer: try: answer[field] = getattr(self, field) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 1db7933d..0323037e 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -497,7 +497,7 @@ class Compute: host = "[{}]".format(host) elif host == "0.0.0.0": host = "127.0.0.1" - return "{}://{}:{}/v2/compute{}".format(self._protocol, host, self._port, path) + return "{}://{}:{}/v3/compute{}".format(self._protocol, host, self._port, path) def get_url(self, path): """ Returns URL for specific path at Compute""" diff --git a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py index fb9fbc99..e06828de 100644 --- a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py +++ b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py @@ -310,7 +310,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM): remaining_try = 300 while remaining_try > 0: try: - async with HTTPClient.get(f"http://127.0.0.1:{api_port}/v2/compute/network/interfaces") as resp: + async with HTTPClient.get(f"http://127.0.0.1:{api_port}/v3/compute/network/interfaces") as resp: if resp.status < 300: try: json_data = await resp.json() diff --git a/gns3server/controller/link.py b/gns3server/controller/link.py index 6d02adee..8e461858 100644 --- a/gns3server/controller/link.py +++ b/gns3server/controller/link.py @@ -345,11 +345,12 @@ class Link: node_id = self.capture_node["node"].id adapter_number = self.capture_node["adapter_number"] port_number = self.capture_node["port_number"] - url = "/projects/{project_id}/{node_type}/nodes/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap".format(project_id=self.project.id, - node_type=node_type, - node_id=node_id, - adapter_number=adapter_number, - port_number=port_number) + url = "/projects/{project_id}/{node_type}/nodes/{node_id}/adapters/{adapter_number}/" \ + "ports/{port_number}/capture/stream".format(project_id=self.project.id, + node_type=node_type, + node_id=node_id, + adapter_number=adapter_number, + port_number=port_number) return compute._getUrl(url) diff --git a/gns3server/controller/template.py b/gns3server/controller/template.py index fd800c21..a5c725de 100644 --- a/gns3server/controller/template.py +++ b/gns3server/controller/template.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2016 GNS3 Technologies Inc. +# Copyright (C) 2020 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 @@ -17,57 +17,14 @@ import copy import uuid -import json -import jsonschema -from gns3server.schemas.cloud_template import CLOUD_TEMPLATE_OBJECT_SCHEMA -from gns3server.schemas.ethernet_switch_template import ETHERNET_SWITCH_TEMPLATE_OBJECT_SCHEMA -from gns3server.schemas.ethernet_hub_template import ETHERNET_HUB_TEMPLATE_OBJECT_SCHEMA -from gns3server.schemas.docker_template import DOCKER_TEMPLATE_OBJECT_SCHEMA -from gns3server.schemas.vpcs_template import VPCS_TEMPLATE_OBJECT_SCHEMA -from gns3server.schemas.traceng_template import TRACENG_TEMPLATE_OBJECT_SCHEMA -from gns3server.schemas.virtualbox_template import VIRTUALBOX_TEMPLATE_OBJECT_SCHEMA -from gns3server.schemas.vmware_template import VMWARE_TEMPLATE_OBJECT_SCHEMA -from gns3server.schemas.iou_template import IOU_TEMPLATE_OBJECT_SCHEMA -from gns3server.schemas.qemu_template import QEMU_TEMPLATE_OBJECT_SCHEMA - -from gns3server.schemas.dynamips_template import ( - DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - C7200_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - C3745_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - C3725_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - C3600_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - C2691_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - C2600_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - C1700_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA -) +from pydantic import ValidationError +from fastapi.encoders import jsonable_encoder +from gns3server import schemas import logging log = logging.getLogger(__name__) - -# Add default values for missing entries in a request, largely taken from jsonschema documentation example -# https://python-jsonschema.readthedocs.io/en/latest/faq/#why-doesn-t-my-schema-s-default-property-set-the-default-on-my-instance -def extend_with_default(validator_class): - - validate_properties = validator_class.VALIDATORS["properties"] - def set_defaults(validator, properties, instance, schema): - if jsonschema.Draft4Validator(schema).is_valid(instance): - # only add default for the matching sub-schema (e.g. when using 'oneOf') - for property, subschema in properties.items(): - if "default" in subschema: - instance.setdefault(property, subschema["default"]) - - for error in validate_properties(validator, properties, instance, schema,): - yield error - - return jsonschema.validators.extend( - validator_class, {"properties" : set_defaults}, - ) - - -ValidatorWithDefaults = extend_with_default(jsonschema.Draft4Validator) - ID_TO_CATEGORY = { 3: "firewall", 2: "guest", @@ -76,27 +33,26 @@ ID_TO_CATEGORY = { } TEMPLATE_TYPE_TO_SHEMA = { - "cloud": CLOUD_TEMPLATE_OBJECT_SCHEMA, - "ethernet_hub": ETHERNET_HUB_TEMPLATE_OBJECT_SCHEMA, - "ethernet_switch": ETHERNET_SWITCH_TEMPLATE_OBJECT_SCHEMA, - "docker": DOCKER_TEMPLATE_OBJECT_SCHEMA, - "dynamips": DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - "vpcs": VPCS_TEMPLATE_OBJECT_SCHEMA, - "traceng": TRACENG_TEMPLATE_OBJECT_SCHEMA, - "virtualbox": VIRTUALBOX_TEMPLATE_OBJECT_SCHEMA, - "vmware": VMWARE_TEMPLATE_OBJECT_SCHEMA, - "iou": IOU_TEMPLATE_OBJECT_SCHEMA, - "qemu": QEMU_TEMPLATE_OBJECT_SCHEMA + "cloud": schemas.CloudTemplate, + "ethernet_hub": schemas.EthernetHubTemplate, + "ethernet_switch": schemas.EthernetSwitchTemplate, + "docker": schemas.DockerTemplate, + "dynamips": schemas.DynamipsTemplate, + "vpcs": schemas.VPCSTemplate, + "virtualbox": schemas.VirtualBoxTemplate, + "vmware": schemas.VMwareTemplate, + "iou": schemas.IOUTemplate, + "qemu": schemas.QemuTemplate } DYNAMIPS_PLATFORM_TO_SHEMA = { - "c7200": C7200_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - "c3745": C3745_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - "c3725": C3725_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - "c3600": C3600_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - "c2691": C2691_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - "c2600": C2600_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA, - "c1700": C1700_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA + "c7200": schemas.C7200DynamipsTemplate, + "c3745": schemas.C3745DynamipsTemplate, + "c3725": schemas.C3725DynamipsTemplate, + "c3600": schemas.C3600DynamipsTemplate, + "c2691": schemas.C2691DynamipsTemplate, + "c2600": schemas.C2600DynamipsTemplate, + "c1700": schemas.C1700DynamipsTemplate } @@ -141,11 +97,18 @@ class Template: self._builtin = builtin if builtin is False: - self.validate_and_apply_defaults(TEMPLATE_TYPE_TO_SHEMA[self.template_type]) - - if self.template_type == "dynamips": - # special case for Dynamips to cover all platform types that contain specific settings - self.validate_and_apply_defaults(DYNAMIPS_PLATFORM_TO_SHEMA[self._settings["platform"]]) + try: + template_schema = TEMPLATE_TYPE_TO_SHEMA[self.template_type] + template_settings_with_defaults = template_schema .parse_obj(self.__json__()) + self._settings = jsonable_encoder(template_settings_with_defaults.dict()) + if self.template_type == "dynamips": + # special case for Dynamips to cover all platform types that contain specific settings + dynamips_template_schema = DYNAMIPS_PLATFORM_TO_SHEMA[self._settings["platform"]] + dynamips_template_settings_with_defaults = dynamips_template_schema.parse_obj(self.__json__()) + self._settings = jsonable_encoder(dynamips_template_settings_with_defaults.dict()) + except ValidationError as e: + print(e) #TODO: handle errors + raise log.debug('Template "{name}" [{id}] loaded'.format(name=self.name, id=self._id)) @@ -179,7 +142,6 @@ class Template: def update(self, **kwargs): - from gns3server.controller import Controller controller = Controller.instance() Controller.instance().check_can_write_config() @@ -187,17 +149,6 @@ class Template: controller.notification.controller_emit("template.updated", self.__json__()) controller.save() - def validate_and_apply_defaults(self, schema): - - validator = ValidatorWithDefaults(schema) - try: - validator.validate(self.__json__()) - except jsonschema.ValidationError as e: - message = "JSON schema error {}".format(e.message) - log.error(message) - log.debug("Input schema: {}".format(json.dumps(schema))) - raise - def __json__(self): """ Template settings. diff --git a/gns3server/controller/template_manager.py b/gns3server/controller/template_manager.py index ddd857bf..663d63e1 100644 --- a/gns3server/controller/template_manager.py +++ b/gns3server/controller/template_manager.py @@ -17,7 +17,7 @@ import copy import uuid -import jsonschema +import pydantic from .controller_error import ControllerError, ControllerNotFoundError from .template import Template @@ -53,8 +53,8 @@ class TemplateManager: try: template = Template(template_settings.get("template_id"), template_settings) self._templates[template.id] = template - except jsonschema.ValidationError as e: - message = "Cannot load template with JSON data '{}': {}".format(template_settings, e.message) + except pydantic.ValidationError as e: + message = "Cannot load template with JSON data '{}': {}".format(template_settings, e) log.warning(message) continue @@ -90,8 +90,8 @@ class TemplateManager: template_id = settings.setdefault("template_id", str(uuid.uuid4())) try: template = Template(template_id, settings) - except jsonschema.ValidationError as e: - message = "JSON schema error adding template with JSON data '{}': {}".format(settings, e.message) + except pydantic.ValidationError as e: + message = "JSON schema error adding template with JSON data '{}': {}".format(settings, e) raise ControllerError(message) from . import Controller diff --git a/gns3server/controller/topology.py b/gns3server/controller/topology.py index 91eca0b7..f934b569 100644 --- a/gns3server/controller/topology.py +++ b/gns3server/controller/topology.py @@ -18,21 +18,22 @@ import os import html import json -import copy import uuid import glob import shutil import zipfile -import jsonschema +import pydantic +from typing import Optional from ..version import __version__ -from ..schemas.topology import TOPOLOGY_SCHEMA -from ..schemas import dynamips_vm from ..utils.qt import qt_font_to_style from ..compute.dynamips import PLATFORMS_DEFAULT_RAM from .controller_error import ControllerError +from gns3server.schemas.topology import Topology +from gns3server.schemas.dynamips_nodes import DynamipsCreate + import logging log = logging.getLogger(__name__) @@ -40,29 +41,21 @@ log = logging.getLogger(__name__) GNS3_FILE_FORMAT_REVISION = 9 +class DynamipsNodeValidation(DynamipsCreate): + name: Optional[str] = None + + def _check_topology_schema(topo): try: - jsonschema.validate(topo, TOPOLOGY_SCHEMA) + Topology.parse_obj(topo) # Check the nodes property against compute schemas for node in topo["topology"].get("nodes", []): - schema = None if node["node_type"] == "dynamips": - schema = copy.deepcopy(dynamips_vm.VM_CREATE_SCHEMA) + DynamipsNodeValidation.parse_obj(node.get("properties", {})) - if schema: - # Properties send to compute but in an other place in topology - delete_properties = ["name", "node_id"] - for prop in delete_properties: - del schema["properties"][prop] - schema["required"] = [p for p in schema["required"] if p not in delete_properties] - - jsonschema.validate(node.get("properties", {}), schema) - - except jsonschema.ValidationError as e: - error = "Invalid data in topology file: {} in schema: {}".format( - e.message, - json.dumps(e.schema)) + except pydantic.ValidationError as e: + error = "Invalid data in topology file: {}".format(e) log.critical(error) raise ControllerError(error) diff --git a/gns3server/endpoints/compute/__init__.py b/gns3server/endpoints/compute/__init__.py index b75d8de9..04c1bfe3 100644 --- a/gns3server/endpoints/compute/__init__.py +++ b/gns3server/endpoints/compute/__init__.py @@ -51,7 +51,7 @@ from . import vpcs_nodes compute_api = FastAPI(title="GNS3 compute API", description="This page describes the private compute API for GNS3. PLEASE DO NOT USE DIRECTLY!", - version="v2") + version="v3") @compute_api.exception_handler(ComputeError) diff --git a/gns3server/endpoints/compute/atm_switch_nodes.py b/gns3server/endpoints/compute/atm_switch_nodes.py index 01fefef8..7b09a5fb 100644 --- a/gns3server/endpoints/compute/atm_switch_nodes.py +++ b/gns3server/endpoints/compute/atm_switch_nodes.py @@ -26,7 +26,7 @@ from fastapi.encoders import jsonable_encoder from fastapi.responses import StreamingResponse from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.dynamips import Dynamips from gns3server.compute.dynamips.nodes.atm_switch import ATMSwitch @@ -186,7 +186,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: ATMSwitch = De await nio.delete() -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -202,7 +202,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": pcap_file_path} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop_capture", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: ATMSwitch = Depends(dep_node)): @@ -214,7 +214,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: ATMSwitch = await node.stop_capture(port_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: ATMSwitch = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/capabilities.py b/gns3server/endpoints/compute/capabilities.py index bf930c38..67f0d567 100644 --- a/gns3server/endpoints/compute/capabilities.py +++ b/gns3server/endpoints/compute/capabilities.py @@ -27,7 +27,7 @@ from fastapi import APIRouter from gns3server.version import __version__ from gns3server.compute import MODULES from gns3server.utils.path import get_default_project_directory -from gns3server.endpoints import schemas +from gns3server import schemas router = APIRouter() diff --git a/gns3server/endpoints/compute/cloud_nodes.py b/gns3server/endpoints/compute/cloud_nodes.py index af22cfa3..631c0341 100644 --- a/gns3server/endpoints/compute/cloud_nodes.py +++ b/gns3server/endpoints/compute/cloud_nodes.py @@ -27,7 +27,7 @@ from fastapi.responses import StreamingResponse from typing import Union from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.builtin import Builtin from gns3server.compute.builtin.nodes.cloud import Cloud @@ -197,7 +197,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: Cloud = Depend await node.remove_nio(port_number) -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -213,7 +213,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": pcap_file_path} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: Cloud = Depends(dep_node)): diff --git a/gns3server/endpoints/compute/compute.py b/gns3server/endpoints/compute/compute.py index 225c9bd9..854428e0 100644 --- a/gns3server/endpoints/compute/compute.py +++ b/gns3server/endpoints/compute/compute.py @@ -33,7 +33,7 @@ from gns3server.utils.interfaces import interfaces from gns3server.compute.qemu import Qemu from gns3server.compute.virtualbox import VirtualBox from gns3server.compute.vmware import VMware -from gns3server.endpoints import schemas +from gns3server import schemas from fastapi import APIRouter, HTTPException, Body, status from fastapi.encoders import jsonable_encoder diff --git a/gns3server/endpoints/compute/docker_nodes.py b/gns3server/endpoints/compute/docker_nodes.py index 199c1664..e88664ef 100644 --- a/gns3server/endpoints/compute/docker_nodes.py +++ b/gns3server/endpoints/compute/docker_nodes.py @@ -26,7 +26,7 @@ from fastapi.encoders import jsonable_encoder from fastapi.responses import StreamingResponse from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.docker import Docker from gns3server.compute.docker.docker_vm import DockerVM @@ -262,7 +262,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: DockerVM = Dep await node.adapter_remove_nio_binding(adapter_number) -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -278,7 +278,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": str(pcap_file_path)} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: DockerVM = Depends(dep_node)): @@ -290,7 +290,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: DockerVM = D await node.stop_capture(adapter_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: DockerVM = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/dynamips_nodes.py b/gns3server/endpoints/compute/dynamips_nodes.py index bee788ba..6ba57047 100644 --- a/gns3server/endpoints/compute/dynamips_nodes.py +++ b/gns3server/endpoints/compute/dynamips_nodes.py @@ -31,7 +31,7 @@ from uuid import UUID from gns3server.compute.dynamips import Dynamips from gns3server.compute.dynamips.nodes.router import Router from gns3server.compute.dynamips.dynamips_error import DynamipsError -from gns3server.endpoints import schemas +from gns3server import schemas router = APIRouter() @@ -219,7 +219,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: Router = Depen await nio.delete() -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -242,7 +242,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": pcap_file_path} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: Router = Depends(dep_node)): @@ -253,7 +253,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: Router = Dep await node.stop_capture(adapter_number, port_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: Router = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/ethernet_hub_nodes.py b/gns3server/endpoints/compute/ethernet_hub_nodes.py index bfb7aef1..06c46248 100644 --- a/gns3server/endpoints/compute/ethernet_hub_nodes.py +++ b/gns3server/endpoints/compute/ethernet_hub_nodes.py @@ -28,7 +28,7 @@ from uuid import UUID from gns3server.compute.dynamips import Dynamips from gns3server.compute.dynamips.nodes.ethernet_hub import EthernetHub -from gns3server.endpoints import schemas +from gns3server import schemas router = APIRouter() @@ -187,7 +187,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: EthernetHub = await nio.delete() -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -203,7 +203,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": pcap_file_path} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: EthernetHub = Depends(dep_node)): @@ -215,7 +215,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: EthernetHub await node.stop_capture(port_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: EthernetHub = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/ethernet_switch_nodes.py b/gns3server/endpoints/compute/ethernet_switch_nodes.py index be7e37aa..051338e3 100644 --- a/gns3server/endpoints/compute/ethernet_switch_nodes.py +++ b/gns3server/endpoints/compute/ethernet_switch_nodes.py @@ -28,7 +28,7 @@ from uuid import UUID from gns3server.compute.dynamips import Dynamips from gns3server.compute.dynamips.nodes.ethernet_switch import EthernetSwitch -from gns3server.endpoints import schemas +from gns3server import schemas router = APIRouter() @@ -186,7 +186,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: EthernetSwitch await nio.delete() -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -202,7 +202,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": pcap_file_path} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int,port_number: int, node: EthernetSwitch = Depends(dep_node)): @@ -214,7 +214,7 @@ async def stop_capture(adapter_number: int,port_number: int, node: EthernetSwitc await node.stop_capture(port_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: EthernetSwitch = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/frame_relay_switch_nodes.py b/gns3server/endpoints/compute/frame_relay_switch_nodes.py index 911c6f08..2728e81b 100644 --- a/gns3server/endpoints/compute/frame_relay_switch_nodes.py +++ b/gns3server/endpoints/compute/frame_relay_switch_nodes.py @@ -26,7 +26,7 @@ from fastapi.encoders import jsonable_encoder from fastapi.responses import StreamingResponse from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.dynamips import Dynamips from gns3server.compute.dynamips.nodes.frame_relay_switch import FrameRelaySwitch @@ -188,7 +188,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: FrameRelaySwit await nio.delete() -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -204,7 +204,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": pcap_file_path} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: FrameRelaySwitch = Depends(dep_node)): @@ -216,7 +216,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: FrameRelaySw await node.stop_capture(port_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: FrameRelaySwitch = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/iou_nodes.py b/gns3server/endpoints/compute/iou_nodes.py index 667bb9e4..be3320d9 100644 --- a/gns3server/endpoints/compute/iou_nodes.py +++ b/gns3server/endpoints/compute/iou_nodes.py @@ -27,7 +27,7 @@ from fastapi.responses import StreamingResponse from typing import Union from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.iou import IOU from gns3server.compute.iou.iou_vm import IOUVM @@ -237,7 +237,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: IOUVM = Depend await node.adapter_remove_nio_binding(adapter_number, port_number) -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -252,7 +252,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": str(pcap_file_path)} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: IOUVM = Depends(dep_node)): @@ -263,7 +263,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: IOUVM = Depe await node.stop_capture(adapter_number, port_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: IOUVM = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/nat_nodes.py b/gns3server/endpoints/compute/nat_nodes.py index a2c40f89..de255126 100644 --- a/gns3server/endpoints/compute/nat_nodes.py +++ b/gns3server/endpoints/compute/nat_nodes.py @@ -27,7 +27,7 @@ from fastapi.responses import StreamingResponse from typing import Union from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.builtin import Builtin from gns3server.compute.builtin.nodes.nat import Nat @@ -192,7 +192,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: Nat = Depends( await node.remove_nio(port_number) -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -208,7 +208,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": pcap_file_path} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: Nat = Depends(dep_node)): @@ -220,7 +220,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: Nat = Depend await node.stop_capture(port_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: Nat = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/projects.py b/gns3server/endpoints/compute/projects.py index 8d392da9..dda59bc7 100644 --- a/gns3server/endpoints/compute/projects.py +++ b/gns3server/endpoints/compute/projects.py @@ -32,7 +32,7 @@ from uuid import UUID from gns3server.compute.project_manager import ProjectManager from gns3server.compute.project import Project -from gns3server.endpoints import schemas +from gns3server import schemas router = APIRouter() diff --git a/gns3server/endpoints/compute/qemu_nodes.py b/gns3server/endpoints/compute/qemu_nodes.py index 222ac001..5e8ca4d0 100644 --- a/gns3server/endpoints/compute/qemu_nodes.py +++ b/gns3server/endpoints/compute/qemu_nodes.py @@ -27,7 +27,7 @@ from fastapi.encoders import jsonable_encoder from fastapi.responses import StreamingResponse from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.project_manager import ProjectManager from gns3server.compute.qemu import Qemu from gns3server.compute.qemu.qemu_vm import QemuVM @@ -252,7 +252,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: QemuVM = Depen await node.adapter_remove_nio_binding(adapter_number) -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -268,7 +268,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": str(pcap_file_path)} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: QemuVM = Depends(dep_node)): @@ -280,7 +280,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: QemuVM = Dep await node.stop_capture(adapter_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: QemuVM = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/virtualbox_nodes.py b/gns3server/endpoints/compute/virtualbox_nodes.py index 661560cf..42b1df5c 100644 --- a/gns3server/endpoints/compute/virtualbox_nodes.py +++ b/gns3server/endpoints/compute/virtualbox_nodes.py @@ -26,7 +26,7 @@ from fastapi.encoders import jsonable_encoder from fastapi.responses import StreamingResponse from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.virtualbox import VirtualBox from gns3server.compute.virtualbox.virtualbox_error import VirtualBoxError from gns3server.compute.project_manager import ProjectManager @@ -260,7 +260,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: VirtualBoxVM = await node.adapter_remove_nio_binding(adapter_number) -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -276,7 +276,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": str(pcap_file_path)} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: VirtualBoxVM = Depends(dep_node)): @@ -288,7 +288,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: VirtualBoxVM await node.stop_capture(adapter_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: VirtualBoxVM = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/vmware_nodes.py b/gns3server/endpoints/compute/vmware_nodes.py index b456ca0c..2c706b77 100644 --- a/gns3server/endpoints/compute/vmware_nodes.py +++ b/gns3server/endpoints/compute/vmware_nodes.py @@ -26,7 +26,7 @@ from fastapi.encoders import jsonable_encoder from fastapi.responses import StreamingResponse from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.vmware import VMware from gns3server.compute.project_manager import ProjectManager from gns3server.compute.vmware.vmware_vm import VMwareVM @@ -225,7 +225,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: VMwareVM = Dep await node.adapter_remove_nio_binding(adapter_number) -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -241,7 +241,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": pcap_file_path} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: VMwareVM = Depends(dep_node)): @@ -253,7 +253,7 @@ async def stop_capture(adapter_number: int, port_number: int, node: VMwareVM = D await node.stop_capture(adapter_number) -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: VMwareVM = Depends(dep_node)): """ diff --git a/gns3server/endpoints/compute/vpcs_nodes.py b/gns3server/endpoints/compute/vpcs_nodes.py index abd64930..ed1483ad 100644 --- a/gns3server/endpoints/compute/vpcs_nodes.py +++ b/gns3server/endpoints/compute/vpcs_nodes.py @@ -26,7 +26,7 @@ from fastapi.encoders import jsonable_encoder from fastapi.responses import StreamingResponse from uuid import UUID -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.compute.vpcs import VPCS from gns3server.compute.vpcs.vpcs_vm import VPCSVM @@ -208,7 +208,7 @@ async def delete_nio(adapter_number: int, port_number: int, node: VPCSVM = Depen await node.port_remove_nio_binding(port_number) -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/start_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start", responses=responses) async def start_capture(adapter_number: int, port_number: int, @@ -224,7 +224,7 @@ async def start_capture(adapter_number: int, return {"pcap_file_path": pcap_file_path} -@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/stop_capture", +@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT, responses=responses) async def stop_capture(adapter_number: int, port_number: int, node: VPCSVM = Depends(dep_node)): @@ -244,7 +244,7 @@ async def reset_console(node: VPCSVM = Depends(dep_node)): await node.reset_console() -@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap", +@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream", responses=responses) async def stream_pcap_file(adapter_number: int, port_number: int, node: VPCSVM = Depends(dep_node)): """ diff --git a/gns3server/endpoints/controller/computes.py b/gns3server/endpoints/controller/computes.py index 8a76b239..8d33e4b6 100644 --- a/gns3server/endpoints/controller/computes.py +++ b/gns3server/endpoints/controller/computes.py @@ -25,22 +25,21 @@ from typing import List, Union from uuid import UUID from gns3server.controller import Controller -from gns3server.endpoints.schemas.common import ErrorMessage -from gns3server.endpoints import schemas +from gns3server import schemas router = APIRouter() responses = { - 404: {"model": ErrorMessage, "description": "Compute not found"} + 404: {"model": schemas.ErrorMessage, "description": "Compute not found"} } @router.post("", status_code=status.HTTP_201_CREATED, response_model=schemas.Compute, - responses={404: {"model": ErrorMessage, "description": "Could not connect to compute"}, - 409: {"model": ErrorMessage, "description": "Could not create compute"}, - 401: {"model": ErrorMessage, "description": "Invalid authentication for compute"}}) + responses={404: {"model": schemas.ErrorMessage, "description": "Could not connect to compute"}, + 409: {"model": schemas.ErrorMessage, "description": "Could not create compute"}, + 401: {"model": schemas.ErrorMessage, "description": "Invalid authentication for compute"}}) async def create_compute(compute_data: schemas.ComputeCreate): """ Create a new compute on the controller. diff --git a/gns3server/endpoints/controller/controller.py b/gns3server/endpoints/controller/controller.py index a1e3d0c9..458eb9e5 100644 --- a/gns3server/endpoints/controller/controller.py +++ b/gns3server/endpoints/controller/controller.py @@ -26,8 +26,7 @@ from gns3server.config import Config from gns3server.controller import Controller from gns3server.version import __version__ from gns3server.controller.controller_error import ControllerError, ControllerForbiddenError -from gns3server.endpoints.schemas.common import ErrorMessage -from gns3server.endpoints import schemas +from gns3server import schemas import logging @@ -38,7 +37,7 @@ router = APIRouter() @router.post("/shutdown", status_code=status.HTTP_204_NO_CONTENT, - responses={403: {"model": ErrorMessage, "description": "Server shutdown not allowed"}}) + responses={403: {"model": schemas.ErrorMessage, "description": "Server shutdown not allowed"}}) async def shutdown(): """ Shutdown the local server @@ -85,7 +84,7 @@ def version(): @router.post("/version", response_model=schemas.Version, response_model_exclude_defaults=True, - responses={409: {"model": ErrorMessage, "description": "Invalid version"}}) + responses={409: {"model": schemas.ErrorMessage, "description": "Invalid version"}}) def check_version(version: schemas.Version): """ Check if version is the same as the server. diff --git a/gns3server/endpoints/controller/drawings.py b/gns3server/endpoints/controller/drawings.py index fbb3967c..2baf14db 100644 --- a/gns3server/endpoints/controller/drawings.py +++ b/gns3server/endpoints/controller/drawings.py @@ -25,18 +25,17 @@ from typing import List from uuid import UUID from gns3server.controller import Controller -from gns3server.endpoints.schemas.common import ErrorMessage -from gns3server.endpoints.schemas.drawings import Drawing +from gns3server import schemas router = APIRouter() responses = { - 404: {"model": ErrorMessage, "description": "Project or drawing not found"} + 404: {"model": schemas.ErrorMessage, "description": "Project or drawing not found"} } @router.get("", - response_model=List[Drawing], + response_model=List[schemas.Drawing], response_model_exclude_unset=True) async def get_drawings(project_id: UUID): """ @@ -49,9 +48,9 @@ async def get_drawings(project_id: UUID): @router.post("", status_code=status.HTTP_201_CREATED, - response_model=Drawing, + response_model=schemas.Drawing, responses=responses) -async def create_drawing(project_id: UUID, drawing_data: Drawing): +async def create_drawing(project_id: UUID, drawing_data: schemas.Drawing): """ Create a new drawing. """ @@ -62,7 +61,7 @@ async def create_drawing(project_id: UUID, drawing_data: Drawing): @router.get("/{drawing_id}", - response_model=Drawing, + response_model=schemas.Drawing, response_model_exclude_unset=True, responses=responses) async def get_drawing(project_id: UUID, drawing_id: UUID): @@ -76,10 +75,10 @@ async def get_drawing(project_id: UUID, drawing_id: UUID): @router.put("/{drawing_id}", - response_model=Drawing, + response_model=schemas.Drawing, response_model_exclude_unset=True, responses=responses) -async def update_drawing(project_id: UUID, drawing_id: UUID, drawing_data: Drawing): +async def update_drawing(project_id: UUID, drawing_id: UUID, drawing_data: schemas.Drawing): """ Update a drawing. """ diff --git a/gns3server/endpoints/controller/gns3vm.py b/gns3server/endpoints/controller/gns3vm.py index 16669350..9910df6b 100644 --- a/gns3server/endpoints/controller/gns3vm.py +++ b/gns3server/endpoints/controller/gns3vm.py @@ -23,7 +23,7 @@ from fastapi import APIRouter from fastapi.encoders import jsonable_encoder from gns3server.controller import Controller -from gns3server.endpoints.schemas.gns3vm import GNS3VM +from gns3server import schemas router = APIRouter() @@ -48,7 +48,7 @@ async def get_vms(engine: str): return vms -@router.get("", response_model=GNS3VM) +@router.get("", response_model=schemas.GNS3VM) async def get_gns3vm_settings(): """ Return the GNS3 VM settings. @@ -57,8 +57,8 @@ async def get_gns3vm_settings(): return Controller.instance().gns3vm.__json__() -@router.put("", response_model=GNS3VM, response_model_exclude_unset=True) -async def update_gns3vm_settings(gns3vm_data: GNS3VM): +@router.put("", response_model=schemas.GNS3VM, response_model_exclude_unset=True) +async def update_gns3vm_settings(gns3vm_data: schemas.GNS3VM): """ Update the GNS3 VM settings. """ diff --git a/gns3server/endpoints/controller/links.py b/gns3server/endpoints/controller/links.py index ff1c393d..0a3730aa 100644 --- a/gns3server/endpoints/controller/links.py +++ b/gns3server/endpoints/controller/links.py @@ -32,8 +32,7 @@ from gns3server.controller import Controller from gns3server.controller.controller_error import ControllerError from gns3server.controller.link import Link from gns3server.utils.http_client import HTTPClient -from gns3server.endpoints.schemas.common import ErrorMessage -from gns3server.endpoints import schemas +from gns3server import schemas import logging log = logging.getLogger(__name__) @@ -41,7 +40,7 @@ log = logging.getLogger(__name__) router = APIRouter() responses = { - 404: {"model": ErrorMessage, "description": "Could not find project or link"} + 404: {"model": schemas.ErrorMessage, "description": "Could not find project or link"} } @@ -70,8 +69,8 @@ async def get_links(project_id: UUID): @router.post("", status_code=status.HTTP_201_CREATED, response_model=schemas.Link, - responses={404: {"model": ErrorMessage, "description": "Could not find project"}, - 409: {"model": ErrorMessage, "description": "Could not create link"}}) + responses={404: {"model": schemas.ErrorMessage, "description": "Could not find project"}, + 409: {"model": schemas.ErrorMessage, "description": "Could not create link"}}) async def create_link(project_id: UUID, link_data: schemas.Link): """ Create a new link. @@ -137,31 +136,6 @@ async def update_link(link_data: schemas.Link, link: Link = Depends(dep_link)): return link.__json__() -@router.post("/{link_id}/start_capture", - status_code=status.HTTP_201_CREATED, - response_model=schemas.Link, - responses=responses) -async def start_capture(capture_data: dict, link: Link = Depends(dep_link)): - """ - Start packet capture on the link. - """ - - await link.start_capture(data_link_type=capture_data.get("data_link_type", "DLT_EN10MB"), - capture_file_name=capture_data.get("capture_file_name")) - return link.__json__() - - -@router.post("/{link_id}/stop_capture", - status_code=status.HTTP_204_NO_CONTENT, - responses=responses) -async def stop_capture(link: Link = Depends(dep_link)): - """ - Stop packet capture on the link. - """ - - await link.stop_capture() - - @router.delete("/{link_id}", status_code=status.HTTP_204_NO_CONTENT, responses=responses) @@ -186,9 +160,34 @@ async def reset_link(link: Link = Depends(dep_link)): return link.__json__() -@router.get("/{link_id}/pcap", +@router.post("/{link_id}/capture/start", + status_code=status.HTTP_201_CREATED, + response_model=schemas.Link, + responses=responses) +async def start_capture(capture_data: dict, link: Link = Depends(dep_link)): + """ + Start packet capture on the link. + """ + + await link.start_capture(data_link_type=capture_data.get("data_link_type", "DLT_EN10MB"), + capture_file_name=capture_data.get("capture_file_name")) + return link.__json__() + + +@router.post("/{link_id}/capture/stop", + status_code=status.HTTP_204_NO_CONTENT, + responses=responses) +async def stop_capture(link: Link = Depends(dep_link)): + """ + Stop packet capture on the link. + """ + + await link.stop_capture() + + +@router.get("/{link_id}/capture/stream", responses=responses) -async def pcap(request: Request, link: Link = Depends(dep_link)): +async def stream_pcap(request: Request, link: Link = Depends(dep_link)): """ Stream the PCAP capture file from compute. """ diff --git a/gns3server/endpoints/controller/nodes.py b/gns3server/endpoints/controller/nodes.py index c2f6cca0..20c7b303 100644 --- a/gns3server/endpoints/controller/nodes.py +++ b/gns3server/endpoints/controller/nodes.py @@ -34,8 +34,7 @@ from gns3server.controller.project import Project from gns3server.utils import force_unix_path from gns3server.utils.http_client import HTTPClient from gns3server.controller.controller_error import ControllerForbiddenError -from gns3server.endpoints.schemas.common import ErrorMessage -from gns3server.endpoints import schemas +from gns3server import schemas import logging log = logging.getLogger(__name__) @@ -80,7 +79,7 @@ class NodeConcurrency(APIRoute): router = APIRouter(route_class=NodeConcurrency) responses = { - 404: {"model": ErrorMessage, "description": "Could not find project or node"} + 404: {"model": schemas.ErrorMessage, "description": "Could not find project or node"} } @@ -105,8 +104,8 @@ async def dep_node(node_id: UUID, project: Project = Depends(dep_project)): @router.post("", status_code=status.HTTP_201_CREATED, response_model=schemas.Node, - responses={404: {"model": ErrorMessage, "description": "Could not find project"}, - 409: {"model": ErrorMessage, "description": "Could not create node"}}) + responses={404: {"model": schemas.ErrorMessage, "description": "Could not find project"}, + 409: {"model": schemas.ErrorMessage, "description": "Could not create node"}}) async def create_node(node_data: schemas.Node, project: Project = Depends(dep_project)): """ Create a new node. @@ -212,7 +211,7 @@ async def update_node(node_data: schemas.NodeUpdate, node: Node = Depends(dep_no @router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT, responses={**responses, - 409: {"model": ErrorMessage, "description": "Cannot delete node"}}) + 409: {"model": schemas.ErrorMessage, "description": "Cannot delete node"}}) async def delete_node(node_id: UUID, project: Project = Depends(dep_project)): """ Delete a node from a project. @@ -381,7 +380,7 @@ async def ws_console(websocket: WebSocket, node: Node = Depends(dep_node)): compute = node.compute await websocket.accept() log.info(f"New client {websocket.client.host}:{websocket.client.port} has connected to controller console WebSocket") - ws_console_compute_url = f"ws://{compute.host}:{compute.port}/v2/compute/projects/" \ + ws_console_compute_url = f"ws://{compute.host}:{compute.port}/v3/compute/projects/" \ f"{node.project.id}/{node.node_type}/nodes/{node.id}/console/ws" async def ws_receive(ws_console_compute): diff --git a/gns3server/endpoints/controller/projects.py b/gns3server/endpoints/controller/projects.py index a4bd174d..6e965833 100644 --- a/gns3server/endpoints/controller/projects.py +++ b/gns3server/endpoints/controller/projects.py @@ -37,8 +37,7 @@ from typing import List, Optional from uuid import UUID from pathlib import Path -from gns3server.endpoints.schemas.common import ErrorMessage -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.controller import Controller from gns3server.controller.project import Project from gns3server.controller.controller_error import ControllerError, ControllerForbiddenError @@ -51,7 +50,7 @@ from gns3server.config import Config router = APIRouter() responses = { - 404: {"model": ErrorMessage, "description": "Could not find project"} + 404: {"model": schemas.ErrorMessage, "description": "Could not find project"} } @@ -83,7 +82,7 @@ def get_projects(): status_code=status.HTTP_201_CREATED, response_model=schemas.Project, response_model_exclude_unset=True, - responses={409: {"model": ErrorMessage, "description": "Could not create project"}}) + responses={409: {"model": schemas.ErrorMessage, "description": "Could not create project"}}) async def create_project(project_data: schemas.ProjectCreate): """ Create a new project. @@ -145,7 +144,7 @@ def get_project_stats(project: Project = Depends(dep_project)): status_code=status.HTTP_204_NO_CONTENT, responses={ **responses, - 409: {"model": ErrorMessage, "description": "Could not close project"} + 409: {"model": schemas.ErrorMessage, "description": "Could not close project"} }) async def close_project(project: Project = Depends(dep_project)): """ @@ -160,7 +159,7 @@ async def close_project(project: Project = Depends(dep_project)): response_model=schemas.Project, responses={ **responses, - 409: {"model": ErrorMessage, "description": "Could not open project"} + 409: {"model": schemas.ErrorMessage, "description": "Could not open project"} }) async def open_project(project: Project = Depends(dep_project)): """ @@ -176,7 +175,7 @@ async def open_project(project: Project = Depends(dep_project)): response_model=schemas.Project, responses={ **responses, - 409: {"model": ErrorMessage, "description": "Could not load project"} + 409: {"model": schemas.ErrorMessage, "description": "Could not load project"} }) async def load_project(path: str = Body(..., embed=True)): """ @@ -346,7 +345,7 @@ async def import_project(project_id: UUID, request: Request, path: Optional[Path response_model=schemas.Project, responses={ **responses, - 409: {"model": ErrorMessage, "description": "Could not duplicate project"} + 409: {"model": schemas.ErrorMessage, "description": "Could not duplicate project"} }) async def duplicate(project_data: schemas.ProjectDuplicate, project: Project = Depends(dep_project)): """ diff --git a/gns3server/endpoints/controller/snapshots.py b/gns3server/endpoints/controller/snapshots.py index c7c57725..19c08419 100644 --- a/gns3server/endpoints/controller/snapshots.py +++ b/gns3server/endpoints/controller/snapshots.py @@ -27,14 +27,13 @@ from typing import List from uuid import UUID from gns3server.controller.project import Project -from gns3server.endpoints.schemas.common import ErrorMessage -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.controller import Controller router = APIRouter() responses = { - 404: {"model": ErrorMessage, "description": "Could not find project or snapshot"} + 404: {"model": schemas.ErrorMessage, "description": "Could not find project or snapshot"} } diff --git a/gns3server/endpoints/controller/symbols.py b/gns3server/endpoints/controller/symbols.py index d6555143..c4d9c0d8 100644 --- a/gns3server/endpoints/controller/symbols.py +++ b/gns3server/endpoints/controller/symbols.py @@ -25,7 +25,7 @@ from fastapi import APIRouter, Request, status from fastapi.responses import FileResponse from gns3server.controller import Controller -from gns3server.endpoints.schemas.common import ErrorMessage +from gns3server import schemas from gns3server.controller.controller_error import ControllerError, ControllerNotFoundError import logging @@ -43,7 +43,7 @@ def get_symbols(): @router.get("/{symbol_id:path}/raw", - responses={404: {"model": ErrorMessage, "description": "Could not find symbol"}}) + responses={404: {"model": schemas.ErrorMessage, "description": "Could not find symbol"}}) async def get_symbol(symbol_id: str): """ Download a symbol file. diff --git a/gns3server/endpoints/controller/templates.py b/gns3server/endpoints/controller/templates.py index b4edd434..cf14f8cb 100644 --- a/gns3server/endpoints/controller/templates.py +++ b/gns3server/endpoints/controller/templates.py @@ -27,25 +27,20 @@ log = logging.getLogger(__name__) from fastapi import APIRouter, Request, Response, HTTPException, status from fastapi.encoders import jsonable_encoder -from typing import Union, List +from typing import List from uuid import UUID -from gns3server.endpoints.schemas.common import ErrorMessage -from gns3server.endpoints import schemas +from gns3server import schemas from gns3server.controller import Controller + router = APIRouter() responses = { - 404: {"model": ErrorMessage, "description": "Could not find template"} + 404: {"model": schemas.ErrorMessage, "description": "Could not find template"} } -#template_create_models = Union[schemas.VPCSTemplateCreate, schemas.CloudTemplateCreate, schemas.IOUTemplateCreate] -#template_update_models = Union[schemas.VPCSTemplateUpdate, schemas.CloudTemplateUpdate, schemas.IOUTemplateUpdate] -#template_response_models = Union[schemas.VPCSTemplate, schemas.CloudTemplate, schemas.IOUTemplate] - - @router.post("/templates", status_code=status.HTTP_201_CREATED, response_model=schemas.Template) @@ -138,7 +133,7 @@ async def duplicate_template(template_id: UUID): @router.post("/projects/{project_id}/templates/{template_id}", response_model=schemas.Node, status_code=status.HTTP_201_CREATED, - responses={404: {"model": ErrorMessage, "description": "Could not find project or template"}}) + responses={404: {"model": schemas.ErrorMessage, "description": "Could not find project or template"}}) async def create_node_from_template(project_id: UUID, template_id: UUID, template_usage: schemas.TemplateUsage): """ Create a new node from a template. diff --git a/gns3server/endpoints/schemas/__init__.py b/gns3server/endpoints/schemas/__init__.py deleted file mode 100644 index bf8a68b0..00000000 --- a/gns3server/endpoints/schemas/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2020 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 . - - -from .version import Version -from .iou_license import IOULicense -from .links import Link -from .common import ErrorMessage -from .computes import ComputeCreate, ComputeUpdate, Compute, AutoIdlePC -from .nodes import NodeUpdate, NodeDuplicate, NodeCapture, Node -from .projects import ProjectCreate, ProjectUpdate, ProjectDuplicate, Project, ProjectFile -from .snapshots import SnapshotCreate, Snapshot -from .templates import TemplateCreate, TemplateUpdate, TemplateUsage, Template -from .capabilities import Capabilities -from .nios import UDPNIO, TAPNIO, EthernetNIO -from .atm_switch_nodes import ATMSwitchCreate, ATMSwitchUpdate, ATMSwitch -from .cloud_nodes import CloudCreate, CloudUpdate, Cloud -from .docker_nodes import DockerCreate, DockerUpdate, Docker -from .dynamips_nodes import DynamipsCreate, DynamipsUpdate, Dynamips -from .ethernet_hub_nodes import EthernetHubCreate, EthernetHubUpdate, EthernetHub -from .ethernet_switch_nodes import EthernetSwitchCreate, EthernetSwitchUpdate, EthernetSwitch -from .frame_relay_switch_nodes import FrameRelaySwitchCreate, FrameRelaySwitchUpdate, FrameRelaySwitch -from .iou_nodes import IOUCreate, IOUUpdate, IOUStart, IOU -from .nat_nodes import NATCreate, NATUpdate, NAT -from .qemu_nodes import QemuCreate, QemuUpdate, Qemu, QemuDiskResize, QemuImageCreate, QemuImageUpdate -from .virtualbox_nodes import VirtualBoxCreate, VirtualBoxUpdate, VirtualBox -from .vmware_nodes import VMwareCreate, VMwareUpdate, VMware -from .vpcs_nodes import VPCSCreate, VPCSUpdate, VPCS -from .vpcs_templates import VPCSTemplateCreate, VPCSTemplateUpdate, VPCSTemplate -from .cloud_templates import CloudTemplateCreate, CloudTemplateUpdate, CloudTemplate -from .iou_templates import IOUTemplateCreate, IOUTemplateUpdate, IOUTemplate diff --git a/gns3server/endpoints/schemas/capabilities.py b/gns3server/endpoints/schemas/capabilities.py deleted file mode 100644 index 6197d93e..00000000 --- a/gns3server/endpoints/schemas/capabilities.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2020 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 . - - -from pydantic import BaseModel, Field -from typing import List - -from .nodes import NodeType - - -class Capabilities(BaseModel): - """ - Capabilities properties. - """ - - version: str = Field(..., description="Compute version number") - node_types: List[NodeType] = Field(..., description="Node types supported by the compute") - platform: str = Field(..., description="Platform where the compute is running") - cpus: int = Field(..., description="Number of CPUs on this compute") - memory: int = Field(..., description="Amount of memory on this compute") - disk_size: int = Field(..., description="Disk size on this compute") diff --git a/gns3server/endpoints/schemas/version.py b/gns3server/endpoints/schemas/version.py deleted file mode 100644 index cb92d953..00000000 --- a/gns3server/endpoints/schemas/version.py +++ /dev/null @@ -1,25 +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 . - -from pydantic import BaseModel, Field -from typing import Optional - - -class Version(BaseModel): - - version: str = Field(..., description="Version number") - local: Optional[bool] = Field(None, description="Whether this is a local server or not") diff --git a/gns3server/schemas/__init__.py b/gns3server/schemas/__init__.py index e69de29b..875ed06c 100644 --- a/gns3server/schemas/__init__.py +++ b/gns3server/schemas/__init__.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020 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 . + + +from .iou_license import IOULicense +from .links import Link +from .common import ErrorMessage +from .version import Version +from .computes import ComputeCreate, ComputeUpdate, AutoIdlePC, Compute +from .templates import TemplateCreate, TemplateUpdate, TemplateUsage, Template +from .drawings import Drawing +from .gns3vm import GNS3VM +from .nodes import NodeUpdate, NodeDuplicate, NodeCapture, Node +from .projects import ProjectCreate, ProjectUpdate, ProjectDuplicate, Project, ProjectFile +from .snapshots import SnapshotCreate, Snapshot +from .capabilities import Capabilities +from .nios import UDPNIO, TAPNIO, EthernetNIO +from .atm_switch_nodes import ATMSwitchCreate, ATMSwitchUpdate, ATMSwitch +from .cloud_nodes import CloudCreate, CloudUpdate, Cloud +from .docker_nodes import DockerCreate, DockerUpdate, Docker +from .dynamips_nodes import DynamipsCreate, DynamipsUpdate, Dynamips +from .ethernet_hub_nodes import EthernetHubCreate, EthernetHubUpdate, EthernetHub +from .ethernet_switch_nodes import EthernetSwitchCreate, EthernetSwitchUpdate, EthernetSwitch +from .frame_relay_switch_nodes import FrameRelaySwitchCreate, FrameRelaySwitchUpdate, FrameRelaySwitch +from .qemu_nodes import QemuCreate, QemuUpdate, QemuImageCreate, QemuImageUpdate, QemuDiskResize, Qemu +from .iou_nodes import IOUCreate, IOUUpdate, IOUStart, IOU +from .nat_nodes import NATCreate, NATUpdate, NAT +from .vpcs_nodes import VPCSCreate, VPCSUpdate, VPCS +from .vmware_nodes import VMwareCreate, VMwareUpdate, VMware +from .virtualbox_nodes import VirtualBoxCreate, VirtualBoxUpdate, VirtualBox + +from .vpcs_templates import VPCSTemplate +from .cloud_templates import CloudTemplate +from .iou_templates import IOUTemplate +from .docker_templates import DockerTemplate +from .ethernet_hub_templates import EthernetHubTemplate +from .ethernet_switch_templates import EthernetSwitchTemplate +from .virtualbox_templates import VirtualBoxTemplate +from .vmware_templates import VMwareTemplate +from .qemu_templates import QemuTemplate +from .dynamips_templates import ( + DynamipsTemplate, + C1700DynamipsTemplate, + C2600DynamipsTemplate, + C2691DynamipsTemplate, + C3600DynamipsTemplate, + C3725DynamipsTemplate, + C3745DynamipsTemplate, + C7200DynamipsTemplate +) diff --git a/gns3server/endpoints/schemas/atm_switch_nodes.py b/gns3server/schemas/atm_switch_nodes.py similarity index 100% rename from gns3server/endpoints/schemas/atm_switch_nodes.py rename to gns3server/schemas/atm_switch_nodes.py diff --git a/gns3server/schemas/capabilities.py b/gns3server/schemas/capabilities.py index 61378299..6197d93e 100644 --- a/gns3server/schemas/capabilities.py +++ b/gns3server/schemas/capabilities.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2015 GNS3 Technologies Inc. +# Copyright (C) 2020 GNS3 Technologies Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -15,40 +15,21 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from .node import NODE_TYPE_SCHEMA + +from pydantic import BaseModel, Field +from typing import List + +from .nodes import NodeType -CAPABILITIES_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Get what a server support", - "type": "object", - "required": ["version", "node_types"], - "properties": { - "version": { - "description": "Version number", - "type": ["string", "null"], - }, - "node_types": { - "type": "array", - "items": NODE_TYPE_SCHEMA, - "description": "Node type supported by the compute" - }, - "platform": { - "type": "string", - "description": "Platform where the compute is running" - }, - "cpus": { - "description": "Number of CPUs on this compute. Read only", - "type": ["integer", "null"], - }, - "memory": { - "description": "Amount of memory on this compute. Read only", - "type": ["integer", "null"], - }, - "disk_size": { - "description": "Disk size on this compute. Read only", - "type": ["integer", "null"], - }, - }, - "additionalProperties": False -} +class Capabilities(BaseModel): + """ + Capabilities properties. + """ + + version: str = Field(..., description="Compute version number") + node_types: List[NodeType] = Field(..., description="Node types supported by the compute") + platform: str = Field(..., description="Platform where the compute is running") + cpus: int = Field(..., description="Number of CPUs on this compute") + memory: int = Field(..., description="Amount of memory on this compute") + disk_size: int = Field(..., description="Disk size on this compute") diff --git a/gns3server/endpoints/schemas/cloud_nodes.py b/gns3server/schemas/cloud_nodes.py similarity index 100% rename from gns3server/endpoints/schemas/cloud_nodes.py rename to gns3server/schemas/cloud_nodes.py diff --git a/gns3server/schemas/cloud_template.py b/gns3server/schemas/cloud_template.py deleted file mode 100644 index b6840074..00000000 --- a/gns3server/schemas/cloud_template.py +++ /dev/null @@ -1,66 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES -from .port import PORT_OBJECT_SCHEMA - - -CLOUD_TEMPLATE_PROPERTIES = { - "ports_mapping": { - "type": "array", - "items": [PORT_OBJECT_SCHEMA], - "default": [] - }, - "remote_console_host": { - "description": "Remote console host or IP", - "type": ["string"], - "minLength": 1, - "default": "127.0.0.1" - }, - "remote_console_port": { - "description": "Console TCP port", - "minimum": 1, - "maximum": 65535, - "type": "integer", - "default": 23 - }, - "remote_console_type": { - "description": "Console type", - "enum": ["telnet", "vnc", "spice", "http", "https", "none"], - "default": "none" - }, - "remote_console_http_path": { - "description": "Path of the remote web interface", - "type": "string", - "minLength": 1, - "default": "/" - }, -} - -CLOUD_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -CLOUD_TEMPLATE_PROPERTIES["category"]["default"] = "guest" -CLOUD_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "Cloud{0}" -CLOUD_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/cloud.svg" - -CLOUD_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A cloud template object", - "type": "object", - "properties": CLOUD_TEMPLATE_PROPERTIES, - "additionalProperties": False -} diff --git a/gns3server/endpoints/schemas/cloud_templates.py b/gns3server/schemas/cloud_templates.py similarity index 57% rename from gns3server/endpoints/schemas/cloud_templates.py rename to gns3server/schemas/cloud_templates.py index 3ce0e05b..99d12322 100644 --- a/gns3server/endpoints/schemas/cloud_templates.py +++ b/gns3server/schemas/cloud_templates.py @@ -17,29 +17,13 @@ from .templates import Category, TemplateBase -from .cloud_nodes import EthernetPort, TAPPort, UDPPort +from .cloud_nodes import EthernetPort, TAPPort, UDPPort, CloudConsoleType from pydantic import Field from typing import Optional, Union, List -from enum import Enum - -from .nodes import NodeType -class RemoteConsoleType(str, Enum): - """ - Supported remote console types for cloud nodes. - """ - - none = "none" - telnet = "telnet" - vnc = "vnc" - spice = "spice" - http = "http" - https = "https" - - -class CloudTemplateBase(TemplateBase): +class CloudTemplate(TemplateBase): category: Optional[Category] = "guest" default_name_format: Optional[str] = "Cloud{0}" @@ -47,28 +31,5 @@ class CloudTemplateBase(TemplateBase): ports_mapping: List[Union[EthernetPort, TAPPort, UDPPort]] = [] remote_console_host: Optional[str] = Field("127.0.0.1", description="Remote console host or IP") remote_console_port: Optional[int] = Field(23, gt=0, le=65535, description="Remote console TCP port") - remote_console_type: Optional[RemoteConsoleType] = Field("none", description="Remote console type") - remote_console_path: Optional[str] = Field("/", description="Path of the remote web interface") - - -class CloudTemplateCreate(CloudTemplateBase): - - name: str - template_type: NodeType - compute_id: str - - -class CloudTemplateUpdate(CloudTemplateBase): - - pass - - -class CloudTemplate(CloudTemplateBase): - - template_id: str - name: str - category: Category - symbol: str - builtin: bool - template_type: NodeType - compute_id: Union[str, None] + remote_console_type: Optional[CloudConsoleType] = Field("none", description="Remote console type") + remote_console_http_path: Optional[str] = Field("/", description="Path of the remote web interface") diff --git a/gns3server/endpoints/schemas/common.py b/gns3server/schemas/common.py similarity index 100% rename from gns3server/endpoints/schemas/common.py rename to gns3server/schemas/common.py diff --git a/gns3server/schemas/compute.py b/gns3server/schemas/compute.py deleted file mode 100644 index 3de0fb70..00000000 --- a/gns3server/schemas/compute.py +++ /dev/null @@ -1,188 +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 . - -import copy -from .capabilities import CAPABILITIES_SCHEMA - -COMPUTE_CREATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to register a GNS3 compute instance", - "type": "object", - "properties": { - "compute_id": { - "description": "Server identifier", - "type": "string" - }, - "name": { - "description": "Server name", - "type": "string" - }, - "protocol": { - "description": "Server protocol", - "enum": ["http", "https"] - }, - "host": { - "description": "Server host", - "type": "string" - }, - "port": { - "description": "Server port", - "type": "integer" - }, - "user": { - "description": "User for authentication", - "type": ["string", "null"] - }, - "password": { - "description": "Password for authentication", - "type": ["string", "null"] - } - }, - "additionalProperties": False, - "required": ["protocol", "host", "port"] -} - -COMPUTE_UPDATE_SCHEMA = copy.deepcopy(COMPUTE_CREATE_SCHEMA) -del COMPUTE_UPDATE_SCHEMA["required"] - -COMPUTE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to a GNS3 compute object instance", - "type": "object", - "properties": { - "compute_id": { - "description": "Server identifier", - "type": "string" - }, - "name": { - "description": "Server name", - "type": "string" - }, - "protocol": { - "description": "Server protocol", - "enum": ["http", "https"] - }, - "host": { - "description": "Server host", - "type": "string" - }, - "port": { - "description": "Server port", - "type": "integer" - }, - "user": { - "description": "User for authentication", - "type": ["string", "null"] - }, - "connected": { - "description": "Whether the controller is connected to the compute or not", - "type": "boolean" - }, - "cpu_usage_percent": { - "description": "CPU usage of the compute. Read only", - "type": ["number", "null"], - "maximum": 100, - "minimum": 0 - }, - "memory_usage_percent": { - "description": "RAM usage of the compute. Read only", - "type": ["number", "null"], - "maximum": 100, - "minimum": 0 - }, - "disk_usage_percent": { - "description": "Disk usage of the compute. Read only", - "type": ["number", "null"], - "maximum": 100, - "minimum": 0 - }, - "last_error": { - "description": "Last error on the compute", - "type": ["string", "null"] - }, - "capabilities": CAPABILITIES_SCHEMA - }, - "additionalProperties": False, - "required": ["compute_id", "protocol", "host", "port", "name"] -} - -COMPUTE_ENDPOINT_OUTPUT_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Output schema for obtaining endpoint on compute", - "type": "object", - "properties": { - "endpoint": { - "description": "URL to endpoint on specific compute and to particular action", - "type": "string" - }, - }, - "additionalProperties": False, -} - -COMPUTE_PORTS_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Output schema for open ports on a compute", - "type": "object", - "properties": { - "console_port_range": { - "description": "Console port range", - "type": "array", - "uniqueItems": True, - "minItems": 2, - "maxItems": 2, - "items": { - "type": "integer", - "minimum": 1, - "maximum": 65535 - } - }, - "console_ports": { - "description": "Console ports used by the compute", - "type": "array", - "uniqueItems": True, - "items": { - "type": "integer", - "minimum": 1, - "maximum": 65535 - } - }, - "udp_port_range": { - "description": "UDP port range", - "type": "array", - "uniqueItems": True, - "minItems": 2, - "maxItems": 2, - "items": { - "type": "integer", - "minimum": 1, - "maximum": 65535 - } - }, - "udp_ports": { - "description": "UDP ports used by the compute", - "type": "array", - "uniqueItems": True, - "items": { - "type": "integer", - "minimum": 1, - "maximum": 65535 - } - }, - }, - "additionalProperties": False, -} - diff --git a/gns3server/endpoints/schemas/computes.py b/gns3server/schemas/computes.py similarity index 87% rename from gns3server/endpoints/schemas/computes.py rename to gns3server/schemas/computes.py index f903e970..92fa5305 100644 --- a/gns3server/endpoints/schemas/computes.py +++ b/gns3server/schemas/computes.py @@ -103,12 +103,12 @@ class Compute(ComputeBase): compute_id: Union[str, UUID] name: str - connected: bool = Field(..., description="Whether the controller is connected to the compute or not") - cpu_usage_percent: float = Field(..., description="CPU usage of the compute", ge=0, le=100) - memory_usage_percent: float = Field(..., description="Memory usage of the compute", ge=0, le=100) - disk_usage_percent: float = Field(..., description="Disk usage of the compute", ge=0, le=100) + connected: Optional[bool] = Field(None, description="Whether the controller is connected to the compute or not") + cpu_usage_percent: Optional[float] = Field(None, description="CPU usage of the compute", ge=0, le=100) + memory_usage_percent: Optional[float] = Field(None, description="Memory usage of the compute", ge=0, le=100) + disk_usage_percent: Optional[float] = Field(None, description="Disk usage of the compute", ge=0, le=100) last_error: Optional[str] = Field(None, description="Last error found on the compute") - capabilities: Capabilities + capabilities: Optional[Capabilities] = None class AutoIdlePC(BaseModel): diff --git a/gns3server/schemas/custom_adapters.py b/gns3server/schemas/custom_adapters.py deleted file mode 100644 index f3472540..00000000 --- a/gns3server/schemas/custom_adapters.py +++ /dev/null @@ -1,49 +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 . - -CUSTOM_ADAPTERS_ARRAY_SCHEMA = { - "type": "array", - "default": [], - "items": { - "type": "object", - "description": "Custom properties", - "properties": { - "adapter_number": { - "type": "integer", - "description": "Adapter number" - }, - "port_name": { - "type": "string", - "description": "Custom port name", - "minLength": 1, - }, - "adapter_type": { - "type": "string", - "description": "Custom adapter type", - "minLength": 1, - }, - "mac_address": { - "description": "Custom MAC address", - "type": "string", - "minLength": 1, - "pattern": "^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$" - }, - }, - "additionalProperties": False, - "required": ["adapter_number"] - }, -} diff --git a/gns3server/endpoints/schemas/docker_nodes.py b/gns3server/schemas/docker_nodes.py similarity index 100% rename from gns3server/endpoints/schemas/docker_nodes.py rename to gns3server/schemas/docker_nodes.py diff --git a/gns3server/schemas/docker_template.py b/gns3server/schemas/docker_template.py deleted file mode 100644 index 5f25d17f..00000000 --- a/gns3server/schemas/docker_template.py +++ /dev/null @@ -1,115 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES -from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA - - -DOCKER_TEMPLATE_PROPERTIES = { - "image": { - "description": "Docker image name", - "type": "string", - "minLength": 1 - }, - "adapters": { - "description": "Number of adapters", - "type": "integer", - "minimum": 0, - "maximum": 99, - "default": 1 - }, - "start_command": { - "description": "Docker CMD entry", - "type": "string", - "default": "" - }, - "environment": { - "description": "Docker environment variables", - "type": "string", - "default": "" - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "vnc", "http", "https", "none"], - "default": "telnet" - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["telnet", "none"], - "default": "none" - }, - "console_auto_start": { - "description": "Automatically start the console when the node has started", - "type": "boolean", - "default": False, - }, - "console_http_port": { - "description": "Internal port in the container for the HTTP server", - "type": "integer", - "minimum": 1, - "maximum": 65535, - "default": 80 - }, - "console_http_path": { - "description": "Path of the web interface", - "type": "string", - "minLength": 1, - "default": "/" - }, - "console_resolution": { - "description": "Console resolution for VNC", - "type": "string", - "pattern": "^[0-9]+x[0-9]+$", - "default": "1024x768" - }, - "extra_hosts": { - "description": "Docker extra hosts (added to /etc/hosts)", - "type": "string", - "default": "" - }, - "extra_volumes": { - "description": "Additional directories to make persistent", - "type": "array", - "default": [] - }, - "memory": { - "description": "Maximum amount of memory the container can use in MB", - "type": "integer", - "default": 0 - }, - "cpus": { - "description": "Maximum amount of CPU resources the container can use", - "type": "number", - "default": 0 - }, - "custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA -} - -DOCKER_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -DOCKER_TEMPLATE_PROPERTIES["category"]["default"] = "guest" -DOCKER_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "{name}-{0}" -DOCKER_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/docker_guest.svg" - -DOCKER_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A Docker template object", - "type": "object", - "properties": DOCKER_TEMPLATE_PROPERTIES, - "required": ["image"], - "additionalProperties": False -} diff --git a/gns3server/schemas/docker_templates.py b/gns3server/schemas/docker_templates.py new file mode 100644 index 00000000..1a4784e4 --- /dev/null +++ b/gns3server/schemas/docker_templates.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020 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 . + + +from .templates import Category, TemplateBase +from .nodes import CustomAdapter +from .docker_nodes import ConsoleType, AuxType + +from pydantic import Field +from typing import Optional, List + + +class DockerTemplate(TemplateBase): + + category: Optional[Category] = "guest" + default_name_format: Optional[str] = "{name}-{0}" + symbol: Optional[str] = ":/symbols/docker_guest.svg" + image: str = Field(..., description="Docker image name") + adapters: Optional[int] = Field(1, ge=0, le=100, description="Number of adapters") + start_command: Optional[str] = Field("", description="Docker CMD entry") + environment: Optional[str] = Field("", description="Docker environment variables") + console_type: Optional[ConsoleType] = Field("telnet", description="Console type") + aux_type: Optional[AuxType] = Field("none", description="Auxiliary console type") + console_auto_start: Optional[bool] = Field(False, description="Automatically start the console when the node has started") + console_http_port: Optional[int] = Field(80, gt=0, le=65535, description="Internal port in the container for the HTTP server") + console_http_path: Optional[str] = Field("/", description="Path of the web interface",) + console_resolution: Optional[str] = Field("1024x768", regex="^[0-9]+x[0-9]+$", description="Console resolution for VNC") + extra_hosts: Optional[str] = Field("", description="Docker extra hosts (added to /etc/hosts)") + extra_volumes: Optional[List] = Field([], description="Additional directories to make persistent") + memory: Optional[int] = Field(0, description="Maximum amount of memory the container can use in MB") + cpus: Optional[int] = Field(0, description="Maximum amount of CPU resources the container can use") + custom_adapters: Optional[List[CustomAdapter]] = Field([], description="Custom adapters") diff --git a/gns3server/schemas/drawing.py b/gns3server/schemas/drawing.py deleted file mode 100644 index 37f8fd6c..00000000 --- a/gns3server/schemas/drawing.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -# -# 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 . - - -DRAWING_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "An drawing object", - "type": "object", - "properties": { - "drawing_id": { - "description": "Drawing UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "project_id": { - "description": "Project UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "x": { - "description": "X property", - "type": "integer" - }, - "y": { - "description": "Y property", - "type": "integer" - }, - "z": { - "description": "Z property", - "type": "integer" - }, - "locked": { - "description": "Whether the element locked or not", - "type": "boolean" - }, - "rotation": { - "description": "Rotation of the element", - "type": "integer", - "minimum": -359, - "maximum": 360 - }, - "svg": { - "description": "SVG content of the drawing", - "type": "string" - } - }, - "additionalProperties": False -} diff --git a/gns3server/endpoints/schemas/drawings.py b/gns3server/schemas/drawings.py similarity index 100% rename from gns3server/endpoints/schemas/drawings.py rename to gns3server/schemas/drawings.py diff --git a/gns3server/endpoints/schemas/dynamips_nodes.py b/gns3server/schemas/dynamips_nodes.py similarity index 82% rename from gns3server/endpoints/schemas/dynamips_nodes.py rename to gns3server/schemas/dynamips_nodes.py index 3f9e244e..24f05a27 100644 --- a/gns3server/endpoints/schemas/dynamips_nodes.py +++ b/gns3server/schemas/dynamips_nodes.py @@ -25,6 +25,20 @@ from uuid import UUID from .nodes import NodeStatus +class DynamipsPlatform(str, Enum): + """ + Supported Dynamips Platforms. + """ + + c7200 = "c7200" + c3725 = "c3725" + c3745 = "c3745" + c3600 = "c3600" + c2691 = "c2691" + c2600 = "c2600" + c1700 = "c1700" + + class DynamipsAdapters(str, Enum): """ Supported Dynamips Network Modules. @@ -56,6 +70,7 @@ class DynamipsAdapters(str, Enum): gt96100_fe = "GT96100-FE" leopard_2fe = "Leopard-2FE" + class DynamipsWics(str, Enum): """ Supported Dynamips WICs. @@ -108,7 +123,7 @@ class DynamipsBase(BaseModel): node_id: Optional[UUID] = None name: Optional[str] = None dynamips_id: Optional[int] = Field(None, description="Dynamips internal ID") - platform: Optional[str] = Field(None, description="Cisco router platform", regex="^c[0-9]{4}$") + platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform") ram: Optional[int] = Field(None, description="Amount of RAM in MB") nvram: Optional[int] = Field(None, description="Amount of NVRAM in KB") image: Optional[Path] = Field(None, description="Path to the IOS image") @@ -133,16 +148,16 @@ class DynamipsBase(BaseModel): aux_type: Optional[DynamipsConsoleType] = Field(None, description="Auxiliary console type") mac_addr: Optional[str] = Field(None, description="Base MAC address", regex="^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$") system_id: Optional[str] = Field(None, description="System ID") - slot0: Optional[str] = Field(None, description="Network module slot 0") - slot1: Optional[str] = Field(None, description="Network module slot 1") - slot2: Optional[str] = Field(None, description="Network module slot 2") - slot3: Optional[str] = Field(None, description="Network module slot 3") - slot4: Optional[str] = Field(None, description="Network module slot 4") - slot5: Optional[str] = Field(None, description="Network module slot 5") - slot6: Optional[str] = Field(None, description="Network module slot 6") - wic0: Optional[str] = Field(None, description="Network module WIC slot 0") - wic1: Optional[str] = Field(None, description="Network module WIC slot 1") - wic2: Optional[str] = Field(None, description="Network module WIC slot 2") + slot0: Optional[DynamipsAdapters] = Field(None, description="Network module slot 0") + slot1: Optional[DynamipsAdapters] = Field(None, description="Network module slot 1") + slot2: Optional[DynamipsAdapters] = Field(None, description="Network module slot 2") + slot3: Optional[DynamipsAdapters] = Field(None, description="Network module slot 3") + slot4: Optional[DynamipsAdapters] = Field(None, description="Network module slot 4") + slot5: Optional[DynamipsAdapters] = Field(None, description="Network module slot 5") + slot6: Optional[DynamipsAdapters] = Field(None, description="Network module slot 6") + wic0: Optional[DynamipsWics] = Field(None, description="Network module WIC slot 0") + wic1: Optional[DynamipsWics] = Field(None, description="Network module WIC slot 1") + wic2: Optional[DynamipsWics] = Field(None, description="Network module WIC slot 2") npe: Optional[DynamipsNPE] = Field(None, description="NPE model") midplane: Optional[DynamipsMidplane] = Field(None, description="Midplane model") sensors: Optional[List] = Field(None, description="Temperature sensors") diff --git a/gns3server/schemas/dynamips_template.py b/gns3server/schemas/dynamips_template.py deleted file mode 100644 index 19f8dc19..00000000 --- a/gns3server/schemas/dynamips_template.py +++ /dev/null @@ -1,404 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES -from .dynamips_vm import DYNAMIPS_ADAPTERS, DYNAMIPS_WICS - - -DYNAMIPS_TEMPLATE_PROPERTIES = { - "platform": { - "description": "Platform type", - "enum": ["c7200", "c3745", "c3725", "c3600", "c2691", "c2600", "c1700"] - }, - "image": { - "description": "Path to the IOS image", - "type": "string", - "minLength": 1 - }, - "mmap": { - "description": "MMAP feature", - "type": "boolean", - "default": True - }, - "exec_area": { - "description": "Exec area value", - "type": "integer", - "default": 64 - }, - "mac_addr": { - "description": "Base MAC address", - "type": "string", - "anyOf": [ - {"pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$"}, - {"pattern": "^$"} - ], - "default": "" - }, - "system_id": { - "description": "System ID", - "type": "string", - "minLength": 1, - "default": "FTX0945W0MY" - }, - "startup_config": { - "description": "IOS startup configuration file", - "type": "string", - "default": "ios_base_startup-config.txt" - }, - "private_config": { - "description": "IOS private configuration file", - "type": "string", - "default": "" - }, - "idlepc": { - "description": "Idle-PC value", - "type": "string", - "pattern": "^(0x[0-9a-fA-F]+)?$", - "default": "" - }, - "idlemax": { - "description": "Idlemax value", - "type": "integer", - "default": 500 - }, - "idlesleep": { - "description": "Idlesleep value", - "type": "integer", - "default": 30 - }, - "disk0": { - "description": "Disk0 size in MB", - "type": "integer", - "default": 0 - }, - "disk1": { - "description": "Disk1 size in MB", - "type": "integer", - "default": 0 - }, - "auto_delete_disks": { - "description": "Automatically delete nvram and disk files", - "type": "boolean", - "default": False - }, - "wic0": DYNAMIPS_WICS, - "wic1": DYNAMIPS_WICS, - "wic2": DYNAMIPS_WICS, - "slot0": DYNAMIPS_ADAPTERS, - "slot1": DYNAMIPS_ADAPTERS, - "slot2": DYNAMIPS_ADAPTERS, - "slot3": DYNAMIPS_ADAPTERS, - "slot4": DYNAMIPS_ADAPTERS, - "slot5": DYNAMIPS_ADAPTERS, - "slot6": DYNAMIPS_ADAPTERS, - "console_type": { - "description": "Console type", - "enum": ["telnet", "none"], - "default": "telnet" - }, - "console_auto_start": { - "description": "Automatically start the console when the node has started", - "type": "boolean", - "default": False - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["telnet", "none"], - "default": "none" - } -} - -DYNAMIPS_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -DYNAMIPS_TEMPLATE_PROPERTIES["category"]["default"] = "router" -DYNAMIPS_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "R{0}" -DYNAMIPS_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/router.svg" - -DYNAMIPS_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A Dynamips template object", - "type": "object", - "properties": DYNAMIPS_TEMPLATE_PROPERTIES, - "required": ["platform", "image"], -} - -C7200_DYNAMIPS_TEMPLATE_PROPERTIES = { - "ram": { - "description": "Amount of RAM in MB", - "type": "integer", - "default": 512 - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer", - "default": 512 - }, - "npe": { - "description": "NPE model", - "enum": ["npe-100", "npe-150", "npe-175", "npe-200", "npe-225", "npe-300", "npe-400", "npe-g2"], - "default": "npe-400" - }, - "midplane": { - "description": "Midplane model", - "enum": ["std", "vxr"], - "default": "vxr" - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean", - "default": True - } -} - -C7200_DYNAMIPS_TEMPLATE_PROPERTIES.update(DYNAMIPS_TEMPLATE_PROPERTIES) - -C7200_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A c7200 Dynamips template object", - "type": "object", - "properties": C7200_DYNAMIPS_TEMPLATE_PROPERTIES, - "additionalProperties": False -} - -C3745_DYNAMIPS_TEMPLATE_PROPERTIES = { - "ram": { - "description": "Amount of RAM in MB", - "type": "integer", - "default": 256 - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer", - "default": 256 - }, - "iomem": { - "description": "I/O memory percentage", - "type": "integer", - "minimum": 0, - "maximum": 100, - "default": 5 - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean", - "default": True - } -} - -C3745_DYNAMIPS_TEMPLATE_PROPERTIES.update(DYNAMIPS_TEMPLATE_PROPERTIES) - -C3745_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A c3745 Dynamips template object", - "type": "object", - "properties": C3745_DYNAMIPS_TEMPLATE_PROPERTIES, - "additionalProperties": False -} - -C3725_DYNAMIPS_TEMPLATE_PROPERTIES = { - "ram": { - "description": "Amount of RAM in MB", - "type": "integer", - "default": 128 - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer", - "default": 256 - }, - "iomem": { - "description": "I/O memory percentage", - "type": "integer", - "minimum": 0, - "maximum": 100, - "default": 5 - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean", - "default": True - } -} - -C3725_DYNAMIPS_TEMPLATE_PROPERTIES.update(DYNAMIPS_TEMPLATE_PROPERTIES) - -C3725_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A c3725 Dynamips template object", - "type": "object", - "properties": C3725_DYNAMIPS_TEMPLATE_PROPERTIES, - "additionalProperties": False -} - -C3600_DYNAMIPS_TEMPLATE_PROPERTIES = { - "chassis": { - "description": "Chassis type", - "enum": ["3620", "3640", "3660"], - "default": "3660" - }, - "ram": { - "description": "Amount of RAM in MB", - "type": "integer", - "default": 192 - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer", - "default": 128 - }, - - "iomem": { - "description": "I/O memory percentage", - "type": "integer", - "minimum": 0, - "maximum": 100, - "default": 5 - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean", - "default": True - } -} - -C3600_DYNAMIPS_TEMPLATE_PROPERTIES.update(DYNAMIPS_TEMPLATE_PROPERTIES) - -C3600_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A c3600 Dynamips template object", - "type": "object", - "properties": C3600_DYNAMIPS_TEMPLATE_PROPERTIES, - "required": ["chassis"], - "additionalProperties": False -} - -C2691_DYNAMIPS_TEMPLATE_PROPERTIES = { - "ram": { - "description": "Amount of RAM in MB", - "type": "integer", - "default": 192 - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer", - "default": 256 - }, - "iomem": { - "description": "I/O memory percentage", - "type": "integer", - "minimum": 0, - "maximum": 100, - "default": 5 - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean", - "default": True - } -} - -C2691_DYNAMIPS_TEMPLATE_PROPERTIES.update(DYNAMIPS_TEMPLATE_PROPERTIES) - -C2691_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A c2691 Dynamips template object", - "type": "object", - "properties": C2691_DYNAMIPS_TEMPLATE_PROPERTIES, - "additionalProperties": False -} - -C2600_DYNAMIPS_TEMPLATE_PROPERTIES = { - "chassis": { - "description": "Chassis type", - "enum": ["2610", "2620", "2610XM", "2620XM", "2650XM", "2621", "2611XM", "2621XM", "2651XM"], - "default": "2651XM" - }, - "ram": { - "description": "Amount of RAM in MB", - "type": "integer", - "default": 160 - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer", - "default": 128 - }, - "iomem": { - "description": "I/O memory percentage", - "type": "integer", - "minimum": 0, - "maximum": 100, - "default": 15 - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean", - "default": True - } -} - -C2600_DYNAMIPS_TEMPLATE_PROPERTIES.update(DYNAMIPS_TEMPLATE_PROPERTIES) - -C2600_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A c2600 Dynamips template object", - "type": "object", - "properties": C2600_DYNAMIPS_TEMPLATE_PROPERTIES, - "required": ["chassis"], - "additionalProperties": False -} - -C1700_DYNAMIPS_TEMPLATE_PROPERTIES = { - "chassis": { - "description": "Chassis type", - "enum": ["1720", "1721", "1750", "1751", "1760"], - "default": "1760" - }, - "ram": { - "description": "Amount of RAM in MB", - "type": "integer", - "default": 160 - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer", - "default": 128 - }, - "iomem": { - "description": "I/O memory percentage", - "type": "integer", - "minimum": 0, - "maximum": 100, - "default": 15 - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean", - "default": False - } -} - -C1700_DYNAMIPS_TEMPLATE_PROPERTIES.update(DYNAMIPS_TEMPLATE_PROPERTIES) - -C1700_DYNAMIPS_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A c1700 Dynamips template object", - "type": "object", - "properties": C1700_DYNAMIPS_TEMPLATE_PROPERTIES, - "required": ["chassis"], - "additionalProperties": False -} diff --git a/gns3server/schemas/dynamips_templates.py b/gns3server/schemas/dynamips_templates.py new file mode 100644 index 00000000..3e09702b --- /dev/null +++ b/gns3server/schemas/dynamips_templates.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020 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 . + +from .templates import Category, TemplateBase +from .dynamips_nodes import ( + DynamipsConsoleType, + DynamipsPlatform, + DynamipsAdapters, + DynamipsWics, + DynamipsNPE, + DynamipsMidplane +) + +from pydantic import Field +from pathlib import Path +from typing import Optional +from enum import Enum + + +class DynamipsTemplate(TemplateBase): + + category: Optional[Category] = "router" + default_name_format: Optional[str] = "R{0}" + symbol: Optional[str] = ":/symbols/router.svg" + platform: DynamipsPlatform = Field(..., description="Cisco router platform") + image: Path = Field(..., description="Path to the IOS image") + exec_area: Optional[int] = Field(64, description="Exec area value") + mmap: Optional[bool] = Field(True, description="MMAP feature") + mac_addr: Optional[str] = Field("", description="Base MAC address", regex="^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$|^$") + system_id: Optional[str] = Field("FTX0945W0MY", description="System ID") + startup_config: Optional[str] = Field("ios_base_startup-config.txt", description="IOS startup configuration file") + private_config: Optional[str] = Field("", description="IOS private configuration file") + idlepc: Optional[str] = Field("", description="Idle-PC value", regex="^(0x[0-9a-fA-F]+)?$|^$") + idlemax: Optional[int] = Field(500, description="Idlemax value") + idlesleep: Optional[int] = Field(30, description="Idlesleep value") + disk0: Optional[int] = Field(0, description="Disk0 size in MB") + disk1: Optional[int] = Field(0, description="Disk1 size in MB") + auto_delete_disks: Optional[bool] = Field(False, description="Automatically delete nvram and disk files") + console_type: Optional[DynamipsConsoleType] = Field("telnet", description="Console type") + console_auto_start: Optional[bool] = Field(False, description="Automatically start the console when the node has started") + aux_type: Optional[DynamipsConsoleType] = Field("none", description="Auxiliary console type") + slot0: Optional[DynamipsAdapters] = Field(None, description="Network module slot 0") + slot1: Optional[DynamipsAdapters] = Field(None, description="Network module slot 1") + slot2: Optional[DynamipsAdapters] = Field(None, description="Network module slot 2") + slot3: Optional[DynamipsAdapters] = Field(None, description="Network module slot 3") + slot4: Optional[DynamipsAdapters] = Field(None, description="Network module slot 4") + slot5: Optional[DynamipsAdapters] = Field(None, description="Network module slot 5") + slot6: Optional[DynamipsAdapters] = Field(None, description="Network module slot 6") + wic0: Optional[DynamipsWics] = Field(None, description="Network module WIC slot 0") + wic1: Optional[DynamipsWics] = Field(None, description="Network module WIC slot 1") + wic2: Optional[DynamipsWics] = Field(None, description="Network module WIC slot 2") + + +class C7200DynamipsTemplate(DynamipsTemplate): + + ram: Optional[int] = Field(512, description="Amount of RAM in MB") + nvram: Optional[int] = Field(512, description="Amount of NVRAM in KB") + npe: Optional[DynamipsNPE] = Field("npe-400", description="NPE model") + midplane: Optional[DynamipsMidplane] = Field("vxr", description="Midplane model") + sparsemem: Optional[bool] = Field(True, description="Sparse memory feature") + + +class C3725DynamipsTemplate(DynamipsTemplate): + + ram: Optional[int] = Field(128, description="Amount of RAM in MB") + nvram: Optional[int] = Field(256, description="Amount of NVRAM in KB") + iomem: Optional[int] = Field(5, ge=0, le=100, description="I/O memory percentage") + sparsemem: Optional[bool] = Field(True, description="Sparse memory feature") + + +class C3745DynamipsTemplate(DynamipsTemplate): + + ram: Optional[int] = Field(256, description="Amount of RAM in MB") + nvram: Optional[int] = Field(256, description="Amount of NVRAM in KB") + iomem: Optional[int] = Field(5, ge=0, le=100, description="I/O memory percentage") + sparsemem: Optional[bool] = Field(True, description="Sparse memory feature") + + +class C3600ChassisType(str, Enum): + + chassis_3620 = "3620" + chassis_3640 = "3640" + chassis_3660 = "3660" + + +class C3600DynamipsTemplate(DynamipsTemplate): + + chassis: Optional[C3600ChassisType] = Field("c3660", description="Chassis type") + ram: Optional[int] = Field(192, description="Amount of RAM in MB") + nvram: Optional[int] = Field(128, description="Amount of NVRAM in KB") + iomem: Optional[int] = Field(5, ge=0, le=100, description="I/O memory percentage") + sparsemem: Optional[bool] = Field(True, description="Sparse memory feature") + + +class C2691DynamipsTemplate(DynamipsTemplate): + + ram: Optional[int] = Field(192, description="Amount of RAM in MB") + nvram: Optional[int] = Field(256, description="Amount of NVRAM in KB") + iomem: Optional[int] = Field(5, ge=0, le=100, description="I/O memory percentage") + sparsemem: Optional[bool] = Field(True, description="Sparse memory feature") + + +class C2600ChassisType(str, Enum): + + chassis_2610 = "2610" + chassis_2620 = "2620" + chassis_2610xm = "2610XM" + chassis_2620xm = "2620XM" + chassis_2650xm = "2650XM" + chassis_2621 = "2621" + chassis_2611xm = "2611XM" + chassis_2621xm = "2621XM" + chassis_2651xm = "2651XM" + + +class C2600DynamipsTemplate(DynamipsTemplate): + + chassis: Optional[C2600ChassisType] = Field("2651XM", description="Chassis type") + ram: Optional[int] = Field(160, description="Amount of RAM in MB") + nvram: Optional[int] = Field(128, description="Amount of NVRAM in KB") + iomem: Optional[int] = Field(15, ge=0, le=100, description="I/O memory percentage") + sparsemem: Optional[bool] = Field(True, description="Sparse memory feature") + + +class C1700ChassisType(str, Enum): + + chassis_1720 = "1720" + chassis_1721 = "1721" + chassis_1750 = "1750" + chassis_1751 = "1751" + chassis_1760 = "1760" + + +class C1700DynamipsTemplate(DynamipsTemplate): + + chassis: Optional[C1700ChassisType] = Field("1760", description="Chassis type") + ram: Optional[int] = Field(160, description="Amount of RAM in MB") + nvram: Optional[int] = Field(128, description="Amount of NVRAM in KB") + iomem: Optional[int] = Field(15, ge=0, le=100, description="I/O memory percentage") + sparsemem: Optional[bool] = Field(False, description="Sparse memory feature") diff --git a/gns3server/schemas/dynamips_vm.py b/gns3server/schemas/dynamips_vm.py deleted file mode 100644 index 2e0b32f9..00000000 --- a/gns3server/schemas/dynamips_vm.py +++ /dev/null @@ -1,774 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2014 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 . - - -DYNAMIPS_ADAPTERS = { - "description": "Dynamips Network Module", - "enum": ["C7200-IO-2FE", - "C7200-IO-FE", - "C7200-IO-GE-E", - "NM-16ESW", - "NM-1E", - "NM-1FE-TX", - "NM-4E", - "NM-4T", - "PA-2FE-TX", - "PA-4E", - "PA-4T+", - "PA-8E", - "PA-8T", - "PA-A1", - "PA-FE-TX", - "PA-GE", - "PA-POS-OC3", - "C2600-MB-2FE", - "C2600-MB-1E", - "C1700-MB-1FE", - "C2600-MB-2E", - "C2600-MB-1FE", - "C1700-MB-WIC1", - "GT96100-FE", - "Leopard-2FE", - ""] -} - -DYNAMIPS_WICS = { - "description": "Dynamips WIC", - "enum": ["WIC-1ENET", - "WIC-1T", - "WIC-2T", - ""] -} - -#TODO: improve schema for Dynamips (match platform specific options, e.g. NPE allowd only for c7200) -VM_CREATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to create a new Dynamips VM instance", - "type": "object", - "properties": { - "node_id": { - "description": "Node UUID", - "oneOf": [ - {"type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"}, - {"type": "integer"} # for legacy projects - ] - }, - "dynamips_id": { - "description": "Dynamips ID", - "type": ["integer", "null"] - }, - "name": { - "description": "Dynamips VM instance name", - "type": "string", - "minLength": 1, - }, - "usage": { - "description": "How to use the Dynamips VM", - "type": "string", - }, - "platform": { - "description": "Cisco router platform", - "type": "string", - "minLength": 1, - "pattern": "^c[0-9]{4}$" - }, - "chassis": { - "description": "Cisco router chassis model", - "type": "string", - "minLength": 1, - "pattern": "^[0-9]{4}(XM)?$" - }, - "image": { - "description": "Path to the IOS image", - "type": "string", - "minLength": 1, - }, - "image_md5sum": { - "description": "Checksum of the IOS image", - "type": ["string", "null"], - "minLength": 1, - }, - "startup_config_content": { - "description": "Content of IOS startup configuration file", - "type": "string", - }, - "private_config_content": { - "description": "Content of IOS private configuration file", - "type": "string", - }, - "ram": { - "description": "Amount of RAM in MB", - "type": "integer" - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer" - }, - "mmap": { - "description": "MMAP feature", - "type": "boolean" - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean" - }, - "clock_divisor": { - "description": "Clock divisor", - "type": "integer" - }, - "idlepc": { - "description": "Idle-PC value", - "type": "string", - "pattern": "^(0x[0-9a-fA-F]+)?$" - }, - "idlemax": { - "description": "Idlemax value", - "type": "integer", - }, - "idlesleep": { - "description": "Idlesleep value", - "type": "integer", - }, - "exec_area": { - "description": "Exec area value", - "type": "integer", - }, - "disk0": { - "description": "Disk0 size in MB", - "type": "integer" - }, - "disk1": { - "description": "Disk1 size in MB", - "type": "integer" - }, - "auto_delete_disks": { - "description": "Automatically delete nvram and disk files", - "type": "boolean" - }, - "console": { - "description": "Console TCP port", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 65535 - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "none"] - }, - "aux": { - "description": "Auxiliary console TCP port", - "type": ["null", "integer"], - "minimum": 1, - "maximum": 65535 - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["telnet", "none"] - }, - "mac_addr": { - "description": "Base MAC address", - "type": ["null", "string"], - "minLength": 1, - "pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$" - }, - "system_id": { - "description": "System ID", - "type": "string", - "minLength": 1, - }, - "slot0": { - "description": "Network module slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot1": { - "description": "Network module slot 1", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot2": { - "description": "Network module slot 2", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot3": { - "description": "Network module slot 3", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot4": { - "description": "Network module slot 4", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot5": { - "description": "Network module slot 5", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot6": { - "description": "Network module slot 6", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "wic0": { - "description": "Network module WIC slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "wic1": { - "description": "Network module WIC slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "wic2": { - "description": "Network module WIC slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - # C7200 properties - "npe": { - "description": "NPE model", - "enum": ["npe-100", - "npe-150", - "npe-175", - "npe-200", - "npe-225", - "npe-300", - "npe-400", - "npe-g2"] - }, - "midplane": { - "description": "Midplane model", - "enum": ["std", "vxr"] - }, - "sensors": { - "description": "Temperature sensors", - "type": "array" - }, - "power_supplies": { - "description": "Power supplies status", - "type": "array" - }, - # I/O memory property for all platforms but C7200 - "iomem": { - "description": "I/O memory percentage", - "type": "integer", - "minimum": 0, - "maximum": 100 - }, - }, - "additionalProperties": False, - "required": ["name", "platform", "image", "ram"] -} - -VM_UPDATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to update a Dynamips VM instance", - "type": "object", - "properties": { - "name": { - "description": "Dynamips VM instance name", - "type": "string", - "minLength": 1, - }, - "usage": { - "description": "How to use the Dynamips VM", - "type": "string", - }, - "platform": { - "description": "Cisco router platform", - "type": "string", - "minLength": 1, - "pattern": "^c[0-9]{4}$" - }, - "chassis": { - "description": "Cisco router chassis model", - "type": "string", - "minLength": 1, - "pattern": "^[0-9]{4}(XM)?$" - }, - "image": { - "description": "Path to the IOS image", - "type": "string", - "minLength": 1, - }, - "image_md5sum": { - "description": "Checksum of the IOS image", - "type": ["string", "null"], - "minLength": 1, - }, - "dynamips_id": { - "description": "Dynamips ID", - "type": "integer" - }, - "ram": { - "description": "Amount of RAM in MB", - "type": "integer" - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer" - }, - "mmap": { - "description": "MMAP feature", - "type": "boolean" - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean" - }, - "clock_divisor": { - "description": "Clock divisor", - "type": "integer" - }, - "idlepc": { - "description": "Idle-PC value", - "type": "string", - "pattern": "^(0x[0-9a-fA-F]+)?$" - }, - "idlemax": { - "description": "Idlemax value", - "type": "integer", - }, - "idlesleep": { - "description": "Idlesleep value", - "type": "integer", - }, - "exec_area": { - "description": "Exec area value", - "type": "integer", - }, - "disk0": { - "description": "Disk0 size in MB", - "type": "integer" - }, - "disk1": { - "description": "Disk1 size in MB", - "type": "integer" - }, - "auto_delete_disks": { - "description": "Automatically delete nvram and disk files", - "type": "boolean" - }, - "console": { - "description": "Console TCP port", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 65535 - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "none"] - }, - "aux": { - "description": "Auxiliary console TCP port", - "type": "integer", - "minimum": 1, - "maximum": 65535 - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["telnet", "none"] - }, - "mac_addr": { - "description": "Base MAC address", - "type": ["null", "string"], - "minLength": 1, - "pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$" - }, - "system_id": { - "description": "System ID", - "type": "string", - "minLength": 1, - }, - "slot0": { - "description": "Network module slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot1": { - "description": "Network module slot 1", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot2": { - "description": "Network module slot 2", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot3": { - "description": "Network module slot 3", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot4": { - "description": "Network module slot 4", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot5": { - "description": "Network module slot 5", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot6": { - "description": "Network module slot 6", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "wic0": { - "description": "Network module WIC slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "wic1": { - "description": "Network module WIC slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "wic2": { - "description": "Network module WIC slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - # C7200 properties - "npe": { - "description": "NPE model", - "enum": ["npe-100", - "npe-150", - "npe-175", - "npe-200", - "npe-225", - "npe-300", - "npe-400", - "npe-g2"] - }, - "midplane": { - "description": "Midplane model", - "enum": ["std", "vxr"] - }, - "sensors": { - "description": "Temperature sensors", - "type": "array" - }, - "power_supplies": { - "description": "Power supplies status", - "type": "array" - }, - # I/O memory property for all platforms but C7200 - "iomem": { - "description": "I/O memory percentage", - "type": "integer", - "minimum": 0, - "maximum": 100 - }, - }, - "additionalProperties": False, -} - - -VM_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Dynamips VM instance", - "type": "object", - "properties": { - "dynamips_id": { - "description": "ID to use with Dynamips", - "type": "integer" - }, - "node_id": { - "description": "Node UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "node_directory": { - "description": "Path to the vm working directory", - "type": "string" - }, - "project_id": { - "description": "Project UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "name": { - "description": "Dynamips VM instance name", - "type": "string", - "minLength": 1, - }, - "usage": { - "description": "How to use the Dynamips VM", - "type": "string", - }, - "status": { - "description": "VM status", - "enum": ["started", "stopped", "suspended"] - }, - "platform": { - "description": "Cisco router platform", - "type": "string", - "minLength": 1, - "pattern": "^c[0-9]{4}$" - }, - "chassis": { - "description": "Cisco router chassis model", - "type": "string", - "minLength": 1, - "pattern": "^[0-9]{4}(XM)?$" - }, - "image": { - "description": "Path to the IOS image", - "type": "string", - "minLength": 1, - }, - "image_md5sum": { - "description": "Checksum of the IOS image", - "type": ["string", "null"], - "minLength": 1, - }, - "ram": { - "description": "Amount of RAM in MB", - "type": "integer" - }, - "nvram": { - "description": "Amount of NVRAM in KB", - "type": "integer" - }, - "mmap": { - "description": "MMAP feature", - "type": "boolean" - }, - "sparsemem": { - "description": "Sparse memory feature", - "type": "boolean" - }, - "clock_divisor": { - "description": "Clock divisor", - "type": "integer" - }, - "idlepc": { - "description": "Idle-PC value", - "type": "string", - "pattern": "^(0x[0-9a-fA-F]+)?$" - }, - "idlemax": { - "description": "Idlemax value", - "type": "integer", - }, - "idlesleep": { - "description": "Idlesleep value", - "type": "integer", - }, - "exec_area": { - "description": "Exec area value", - "type": "integer", - }, - "disk0": { - "description": "Disk0 size in MB", - "type": "integer" - }, - "disk1": { - "description": "Disk1 size in MB", - "type": "integer" - }, - "auto_delete_disks": { - "description": "Automatically delete nvram and disk files", - "type": "boolean" - }, - "console": { - "description": "Console TCP port", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 65535 - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "none"] - }, - "aux": { - "description": "Auxiliary console TCP port", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 65535 - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["telnet", "none"] - }, - "mac_addr": { - "description": "Base MAC address", - "type": ["null", "string"] - #"minLength": 1, - #"pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$" - }, - "system_id": { - "description": "System ID", - "type": "string", - "minLength": 1, - }, - "slot0": { - "description": "Network module slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot1": { - "description": "Network module slot 1", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot2": { - "description": "Network module slot 2", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot3": { - "description": "Network module slot 3", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot4": { - "description": "Network module slot 4", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot5": { - "description": "Network module slot 5", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "slot6": { - "description": "Network module slot 6", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "wic0": { - "description": "Network module WIC slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "wic1": { - "description": "Network module WIC slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - "wic2": { - "description": "Network module WIC slot 0", - "oneOf": [ - {"type": "string"}, - {"type": "null"} - ] - }, - # C7200 properties - "npe": { - "description": "NPE model", - "enum": ["npe-100", - "npe-150", - "npe-175", - "npe-200", - "npe-225", - "npe-300", - "npe-400", - "npe-g2"] - }, - "midplane": { - "description": "Midplane model", - "enum": ["std", "vxr"] - }, - "sensors": { - "description": "Temperature sensors", - "type": "array" - }, - "power_supplies": { - "description": "Power supplies status", - "type": "array" - }, - # I/O memory property for all platforms but C7200 - "iomem": { - "description": "I/O memory percentage", - "type": "integer", - "minimum": 0, - "maximum": 100 - }, - }, - "additionalProperties": False, - "required": ["name", "node_id", "project_id", "dynamips_id", "console", "console_type"] -} diff --git a/gns3server/endpoints/schemas/ethernet_hub_nodes.py b/gns3server/schemas/ethernet_hub_nodes.py similarity index 100% rename from gns3server/endpoints/schemas/ethernet_hub_nodes.py rename to gns3server/schemas/ethernet_hub_nodes.py diff --git a/gns3server/schemas/ethernet_hub_template.py b/gns3server/schemas/ethernet_hub_template.py deleted file mode 100644 index f7a5edcd..00000000 --- a/gns3server/schemas/ethernet_hub_template.py +++ /dev/null @@ -1,80 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES - - -ETHERNET_HUB_TEMPLATE_PROPERTIES = { - "ports_mapping": { - "type": "array", - "default": [{"port_number": 0, - "name": "Ethernet0" - }, - {"port_number": 1, - "name": "Ethernet1" - }, - {"port_number": 2, - "name": "Ethernet2" - }, - {"port_number": 3, - "name": "Ethernet3" - }, - {"port_number": 4, - "name": "Ethernet4" - }, - {"port_number": 5, - "name": "Ethernet5" - }, - {"port_number": 6, - "name": "Ethernet6" - }, - {"port_number": 7, - "name": "Ethernet7" - } - ], - "items": [ - {"type": "object", - "oneOf": [{"description": "Ethernet port", - "properties": {"name": {"description": "Port name", - "type": "string", - "minLength": 1}, - "port_number": { - "description": "Port number", - "type": "integer", - "minimum": 0} - }, - "required": ["name", "port_number"], - "additionalProperties": False} - ], - } - ] - } -} - -ETHERNET_HUB_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -ETHERNET_HUB_TEMPLATE_PROPERTIES["category"]["default"] = "switch" -ETHERNET_HUB_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "Hub{0}" -ETHERNET_HUB_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/hub.svg" - -ETHERNET_HUB_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "An Ethernet hub template object", - "type": "object", - "properties": ETHERNET_HUB_TEMPLATE_PROPERTIES, - "additionalProperties": False -} diff --git a/gns3server/schemas/ethernet_hub_templates.py b/gns3server/schemas/ethernet_hub_templates.py new file mode 100644 index 00000000..0ca7542c --- /dev/null +++ b/gns3server/schemas/ethernet_hub_templates.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020 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 . + + +from .templates import Category, TemplateBase +from .ethernet_hub_nodes import EthernetHubPort + +from pydantic import Field +from typing import Optional, List + + +DEFAULT_PORTS = [ + dict(port_number=0, name="Ethernet0"), + dict(port_number=1, name="Ethernet1"), + dict(port_number=2, name="Ethernet2"), + dict(port_number=3, name="Ethernet3"), + dict(port_number=4, name="Ethernet4"), + dict(port_number=5, name="Ethernet5"), + dict(port_number=6, name="Ethernet6"), + dict(port_number=7, name="Ethernet7") +] + + +class EthernetHubTemplate(TemplateBase): + + category: Optional[Category] = "switch" + default_name_format: Optional[str] = "Hub{0}" + symbol: Optional[str] = ":/symbols/hub.svg" + ports_mapping: Optional[List[EthernetHubPort]] = Field(DEFAULT_PORTS, description="Ports") diff --git a/gns3server/endpoints/schemas/ethernet_switch_nodes.py b/gns3server/schemas/ethernet_switch_nodes.py similarity index 100% rename from gns3server/endpoints/schemas/ethernet_switch_nodes.py rename to gns3server/schemas/ethernet_switch_nodes.py diff --git a/gns3server/schemas/ethernet_switch_template.py b/gns3server/schemas/ethernet_switch_template.py deleted file mode 100644 index e2473220..00000000 --- a/gns3server/schemas/ethernet_switch_template.py +++ /dev/null @@ -1,127 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES - - -ETHERNET_SWITCH_TEMPLATE_PROPERTIES = { - "ports_mapping": { - "type": "array", - "default": [{"ethertype": "", - "name": "Ethernet0", - "vlan": 1, - "type": "access", - "port_number": 0 - }, - {"ethertype": "", - "name": "Ethernet1", - "vlan": 1, - "type": "access", - "port_number": 1 - }, - {"ethertype": "", - "name": "Ethernet2", - "vlan": 1, - "type": "access", - "port_number": 2 - }, - {"ethertype": "", - "name": "Ethernet3", - "vlan": 1, - "type": "access", - "port_number": 3 - }, - {"ethertype": "", - "name": "Ethernet4", - "vlan": 1, - "type": "access", - "port_number": 4 - }, - {"ethertype": "", - "name": "Ethernet5", - "vlan": 1, - "type": "access", - "port_number": 5 - }, - {"ethertype": "", - "name": "Ethernet6", - "vlan": 1, - "type": "access", - "port_number": 6 - }, - {"ethertype": "", - "name": "Ethernet7", - "vlan": 1, - "type": "access", - "port_number": 7 - } - ], - "items": [ - {"type": "object", - "oneOf": [ - { - "description": "Ethernet port", - "properties": { - "name": { - "description": "Port name", - "type": "string", - "minLength": 1 - }, - "port_number": { - "description": "Port number", - "type": "integer", - "minimum": 0 - }, - "type": { - "description": "Port type", - "enum": ["access", "dot1q", "qinq"], - }, - "vlan": {"description": "VLAN number", - "type": "integer", - "minimum": 1 - }, - "ethertype": { - "description": "QinQ Ethertype", - "enum": ["", "0x8100", "0x88A8", "0x9100", "0x9200"], - }, - }, - "required": ["name", "port_number", "type"], - "additionalProperties": False - }, - ]}, - ] - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "none"], - "default": "none" - }, -} - -ETHERNET_SWITCH_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -ETHERNET_SWITCH_TEMPLATE_PROPERTIES["category"]["default"] = "switch" -ETHERNET_SWITCH_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "Switch{0}" -ETHERNET_SWITCH_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/ethernet_switch.svg" - -ETHERNET_SWITCH_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "An Ethernet switch template object", - "type": "object", - "properties": ETHERNET_SWITCH_TEMPLATE_PROPERTIES, - "additionalProperties": False -} diff --git a/gns3server/schemas/ethernet_switch_templates.py b/gns3server/schemas/ethernet_switch_templates.py new file mode 100644 index 00000000..f605d4fe --- /dev/null +++ b/gns3server/schemas/ethernet_switch_templates.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020 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 . + + +from .templates import Category, TemplateBase +from .ethernet_switch_nodes import EthernetSwitchPort + +from pydantic import Field +from typing import Optional, List +from enum import Enum + +DEFAULT_PORTS = [ + dict(port_number=0, name="Ethernet0", vlan=1, type="access", ethertype=""), + dict(port_number=1, name="Ethernet1", vlan=1, type="access", ethertype=""), + dict(port_number=2, name="Ethernet2", vlan=1, type="access", ethertype=""), + dict(port_number=3, name="Ethernet3", vlan=1, type="access", ethertype=""), + dict(port_number=4, name="Ethernet4", vlan=1, type="access", ethertype=""), + dict(port_number=5, name="Ethernet5", vlan=1, type="access", ethertype=""), + dict(port_number=6, name="Ethernet6", vlan=1, type="access", ethertype=""), + dict(port_number=7, name="Ethernet7", vlan=1, type="access", ethertype="") +] + + +class ConsoleType(str, Enum): + """ + Supported console types for Ethernet switch nodes. + """ + + none = "none" + telnet = "telnet" + + +class EthernetSwitchTemplate(TemplateBase): + + category: Optional[Category] = "switch" + default_name_format: Optional[str] = "Switch{0}" + symbol: Optional[str] = ":/symbols/ethernet_switch.svg" + ports_mapping: Optional[List[EthernetSwitchPort]] = Field(DEFAULT_PORTS, description="Ports") + console_type: Optional[ConsoleType] = Field("none", description="Console type") diff --git a/gns3server/schemas/filter.py b/gns3server/schemas/filter.py deleted file mode 100644 index d7f09972..00000000 --- a/gns3server/schemas/filter.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2017 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 . - - -FILTER_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Packet filter. This allow to simulate latency and errors", - "type": "object" -} diff --git a/gns3server/endpoints/schemas/filters.py b/gns3server/schemas/filters.py similarity index 100% rename from gns3server/endpoints/schemas/filters.py rename to gns3server/schemas/filters.py diff --git a/gns3server/endpoints/schemas/frame_relay_switch_nodes.py b/gns3server/schemas/frame_relay_switch_nodes.py similarity index 100% rename from gns3server/endpoints/schemas/frame_relay_switch_nodes.py rename to gns3server/schemas/frame_relay_switch_nodes.py diff --git a/gns3server/endpoints/schemas/gns3vm.py b/gns3server/schemas/gns3vm.py similarity index 100% rename from gns3server/endpoints/schemas/gns3vm.py rename to gns3server/schemas/gns3vm.py diff --git a/gns3server/endpoints/schemas/iou_license.py b/gns3server/schemas/iou_license.py similarity index 100% rename from gns3server/endpoints/schemas/iou_license.py rename to gns3server/schemas/iou_license.py diff --git a/gns3server/endpoints/schemas/iou_nodes.py b/gns3server/schemas/iou_nodes.py similarity index 100% rename from gns3server/endpoints/schemas/iou_nodes.py rename to gns3server/schemas/iou_nodes.py diff --git a/gns3server/schemas/iou_template.py b/gns3server/schemas/iou_template.py deleted file mode 100644 index aadfaf97..00000000 --- a/gns3server/schemas/iou_template.py +++ /dev/null @@ -1,92 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES - - -IOU_TEMPLATE_PROPERTIES = { - "path": { - "description": "Path of IOU executable", - "type": "string", - "minLength": 1 - }, - "ethernet_adapters": { - "description": "Number of ethernet adapters", - "type": "integer", - "default": 2 - }, - "serial_adapters": { - "description": "Number of serial adapters", - "type": "integer", - "default": 2 - }, - "ram": { - "description": "RAM in MB", - "type": "integer", - "default": 256 - }, - "nvram": { - "description": "NVRAM in KB", - "type": "integer", - "default": 128 - }, - "use_default_iou_values": { - "description": "Use default IOU values", - "type": "boolean", - "default": True - }, - "startup_config": { - "description": "Startup-config of IOU", - "type": "string", - "default": "iou_l3_base_startup-config.txt" - }, - "private_config": { - "description": "Private-config of IOU", - "type": "string", - "default": "" - }, - "l1_keepalives": { - "description": "Always keep up Ethernet interface (does not always work)", - "type": "boolean", - "default": False - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "none"], - "default": "telnet" - }, - "console_auto_start": { - "description": "Automatically start the console when the node has started", - "type": "boolean", - "default": False - }, -} - -IOU_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -IOU_TEMPLATE_PROPERTIES["category"]["default"] = "router" -IOU_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "IOU{0}" -IOU_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/multilayer_switch.svg" - -IOU_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A IOU template object", - "type": "object", - "properties": IOU_TEMPLATE_PROPERTIES, - "required": ["path"], - "additionalProperties": False -} diff --git a/gns3server/endpoints/schemas/iou_templates.py b/gns3server/schemas/iou_templates.py similarity index 76% rename from gns3server/endpoints/schemas/iou_templates.py rename to gns3server/schemas/iou_templates.py index eaf90182..aef82181 100644 --- a/gns3server/endpoints/schemas/iou_templates.py +++ b/gns3server/schemas/iou_templates.py @@ -17,30 +17,18 @@ from .templates import Category, TemplateBase +from .iou_nodes import ConsoleType from pydantic import Field from pathlib import Path -from typing import Optional, Union -from enum import Enum - -from .nodes import NodeType +from typing import Optional -class ConsoleType(str, Enum): - """ - Supported console types for IOU nodes - """ - - none = "none" - telnet = "telnet" - - -class IOUTemplateBase(TemplateBase): +class IOUTemplate(TemplateBase): category: Optional[Category] = "router" default_name_format: Optional[str] = "IOU{0}" symbol: Optional[str] = ":/symbols/multilayer_switch.svg" - path: Path = Field(..., description="Path of IOU executable") ethernet_adapters: Optional[int] = Field(2, description="Number of ethernet adapters") serial_adapters: Optional[int] = Field(2, description="Number of serial adapters") @@ -53,25 +41,3 @@ class IOUTemplateBase(TemplateBase): console_type: Optional[ConsoleType] = Field("telnet", description="Console type") console_auto_start: Optional[bool] = Field(False, description="Automatically start the console when the node has started") - -class IOUTemplateCreate(IOUTemplateBase): - - name: str - template_type: NodeType - compute_id: str - - -class IOUTemplateUpdate(IOUTemplateBase): - - pass - - -class IOUTemplate(IOUTemplateBase): - - template_id: str - name: str - category: Category - symbol: str - builtin: bool - template_type: NodeType - compute_id: Union[str, None] diff --git a/gns3server/schemas/label.py b/gns3server/schemas/label.py deleted file mode 100644 index 503ea64b..00000000 --- a/gns3server/schemas/label.py +++ /dev/null @@ -1,45 +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 . - -LABEL_OBJECT_SCHEMA = { - "type": "object", - "properties": { - "text": {"type": "string"}, - "style": { - "description": "SVG style attribute. Apply default style if null", - "type": ["string", "null"] - }, - "x": { - "description": "Relative X position of the label. Center it if null", - "type": ["integer", "null"] - }, - "y": { - "description": "Relative Y position of the label", - "type": "integer" - }, - "rotation": { - "description": "Rotation of the label", - "type": "integer", - "minimum": -359, - "maximum": 360 - }, - }, - "required": [ - "text" - ], - "additionalProperties": False -} diff --git a/gns3server/schemas/link.py b/gns3server/schemas/link.py deleted file mode 100644 index 6dd5ffe4..00000000 --- a/gns3server/schemas/link.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python -# -# 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 . - -from .label import LABEL_OBJECT_SCHEMA -from .filter import FILTER_OBJECT_SCHEMA - -LINK_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A link object", - "type": "object", - "properties": { - "link_id": { - "description": "Link UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "project_id": { - "description": "Project UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "nodes": { - "description": "List of the VMS", - "type": "array", - "items": { - "type": "object", - "properties": { - "node_id": { - "description": "Node UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "adapter_number": { - "description": "Adapter number", - "type": "integer" - }, - "port_number": { - "description": "Port number", - "type": "integer" - }, - "label": LABEL_OBJECT_SCHEMA - }, - "required": ["node_id", "adapter_number", "port_number"], - "additionalProperties": False - } - }, - "suspend": { - "type": "boolean", - "description": "Suspend the link" - }, - "filters": FILTER_OBJECT_SCHEMA, - "capturing": { - "description": "Read only property. True if a capture running on the link", - "type": "boolean" - }, - "capture_file_name": { - "description": "Read only property. The name of the capture file if a capture is running", - "type": ["string", "null"] - }, - "capture_file_path": { - "description": "Read only property. The full path of the capture file if a capture is running", - "type": ["string", "null"] - }, - "capture_compute_id": { - "description": "Read only property. The compute identifier where a capture is running", - "type": ["string", "null"] - }, - "link_type": { - "description": "Type of link", - "enum": ["ethernet", "serial"] - } - }, - "additionalProperties": False -} - - -LINK_CAPTURE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to start a packet capture on a link", - "type": "object", - "properties": { - "data_link_type": { - "description": "PCAP data link type (http://www.tcpdump.org/linktypes.html)", - "enum": ["DLT_ATM_RFC1483", "DLT_EN10MB", "DLT_FRELAY", "DLT_C_HDLC", "DLT_PPP_SERIAL"] - }, - "capture_file_name": { - "description": "Read only property. The name of the capture file if capture is running", - "type": "string" - } - }, - "additionalProperties": False -} diff --git a/gns3server/endpoints/schemas/links.py b/gns3server/schemas/links.py similarity index 100% rename from gns3server/endpoints/schemas/links.py rename to gns3server/schemas/links.py diff --git a/gns3server/endpoints/schemas/nat_nodes.py b/gns3server/schemas/nat_nodes.py similarity index 100% rename from gns3server/endpoints/schemas/nat_nodes.py rename to gns3server/schemas/nat_nodes.py diff --git a/gns3server/schemas/nio.py b/gns3server/schemas/nio.py deleted file mode 100644 index edee0eab..00000000 --- a/gns3server/schemas/nio.py +++ /dev/null @@ -1,192 +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 . - -from .filter import FILTER_OBJECT_SCHEMA - - -NIO_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to add a NIO for a VM instance", - "type": "object", - "definitions": { - "UDP": { - "description": "UDP Network Input/Output", - "properties": { - "type": { - "enum": ["nio_udp"] - }, - "lport": { - "description": "Local port", - "type": "integer", - "minimum": 1, - "maximum": 65535 - }, - "rhost": { - "description": "Remote host", - "type": "string", - "minLength": 1 - }, - "rport": { - "description": "Remote port", - "type": "integer", - "minimum": 1, - "maximum": 65535 - }, - "suspend": { - "type": "boolean", - "description": "Suspend the link" - }, - "filters": FILTER_OBJECT_SCHEMA - }, - "required": ["type", "lport", "rhost", "rport"], - "additionalProperties": False - }, - "Ethernet": { - "description": "Generic Ethernet Network Input/Output", - "properties": { - "type": { - "enum": ["nio_generic_ethernet", "nio_ethernet"] - }, - "ethernet_device": { - "description": "Ethernet device name e.g. eth0", - "type": "string", - "minLength": 1 - }, - }, - "required": ["type", "ethernet_device"], - "additionalProperties": False - }, - "LinuxEthernet": { - "description": "Linux Ethernet Network Input/Output", - "properties": { - "type": { - "enum": ["nio_linux_ethernet"] - }, - "ethernet_device": { - "description": "Ethernet device name e.g. eth0", - "type": "string", - "minLength": 1 - }, - }, - "required": ["type", "ethernet_device"], - "additionalProperties": False - }, - "NAT": { - "description": "NAT Network Input/Output", - "properties": { - "type": { - "enum": ["nio_nat"] - }, - }, - "required": ["type"], - "additionalProperties": False - }, - "TAP": { - "description": "TAP Network Input/Output", - "properties": { - "type": { - "enum": ["nio_tap"] - }, - "tap_device": { - "description": "TAP device name e.g. tap0", - "type": "string", - "minLength": 1 - }, - }, - "required": ["type", "tap_device"], - "additionalProperties": False - }, - "UNIX": { - "description": "UNIX Network Input/Output", - "properties": { - "type": { - "enum": ["nio_unix"] - }, - "local_file": { - "description": "path to the UNIX socket file (local)", - "type": "string", - "minLength": 1 - }, - "remote_file": { - "description": "path to the UNIX socket file (remote)", - "type": "string", - "minLength": 1 - }, - }, - "required": ["type", "local_file", "remote_file"], - "additionalProperties": False - }, - "VDE": { - "description": "VDE Network Input/Output", - "properties": { - "type": { - "enum": ["nio_vde"] - }, - "control_file": { - "description": "path to the VDE control file", - "type": "string", - "minLength": 1 - }, - "local_file": { - "description": "path to the VDE control file", - "type": "string", - "minLength": 1 - }, - }, - "required": ["type", "control_file", "local_file"], - "additionalProperties": False - }, - "VMNET": { - "description": "VMNET Network Input/Output", - "properties": { - "type": { - "enum": ["nio_vmnet"] - }, - "vmnet": { - "description": "VMnet interface name e.g. vmnet12", - "type": "string", - "minLength": 1 - }, - }, - "required": ["type", "vmnet"], - "additionalProperties": False - }, - "NULL": { - "description": "NULL Network Input/Output", - "properties": { - "type": { - "enum": ["nio_null"] - }, - }, - "required": ["type"], - "additionalProperties": False - }, - }, - "oneOf": [ - {"$ref": "#/definitions/UDP"}, - {"$ref": "#/definitions/Ethernet"}, - {"$ref": "#/definitions/LinuxEthernet"}, - {"$ref": "#/definitions/NAT"}, - {"$ref": "#/definitions/TAP"}, - {"$ref": "#/definitions/UNIX"}, - {"$ref": "#/definitions/VDE"}, - {"$ref": "#/definitions/VMNET"}, - {"$ref": "#/definitions/NULL"}, - ], - "additionalProperties": True, - "required": ["type"] -} diff --git a/gns3server/endpoints/schemas/nios.py b/gns3server/schemas/nios.py similarity index 100% rename from gns3server/endpoints/schemas/nios.py rename to gns3server/schemas/nios.py diff --git a/gns3server/schemas/node.py b/gns3server/schemas/node.py deleted file mode 100644 index d7d92583..00000000 --- a/gns3server/schemas/node.py +++ /dev/null @@ -1,301 +0,0 @@ -#!/usr/bin/env python -# -# 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 . - -import copy -from .label import LABEL_OBJECT_SCHEMA -from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA - -NODE_TYPE_SCHEMA = { - "description": "Type of node", - "enum": [ - "cloud", - "nat", - "ethernet_hub", - "ethernet_switch", - "frame_relay_switch", - "atm_switch", - "docker", - "dynamips", - "vpcs", - "traceng", - "virtualbox", - "vmware", - "iou", - "qemu" - ] -} - -NODE_LIST_IMAGES_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "List of binary images", - "type": "array", - "items": [ - { - "type": "object", - "properties": { - "filename": { - "description": "Image filename", - "type": "string", - "minLength": 1 - }, - "path": { - "description": "Image path", - "type": "string", - "minLength": 1 - }, - "md5sum": { - "description": "md5sum of the image if available", - "type": ["string", "null"], - "minLength": 1 - }, - "filesize": { - "description": "size of the image if available", - "type": ["integer", "null"], - "minimum": 0 - } - }, - "required": ["filename", "path"], - "additionalProperties": False - } - ], - "additionalProperties": False, -} - - -NODE_CAPTURE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to start a packet capture on a port", - "type": "object", - "properties": { - "capture_file_name": { - "description": "Capture file name", - "type": "string", - "minLength": 1, - }, - "data_link_type": { - "description": "PCAP data link type (http://www.tcpdump.org/linktypes.html)", - "enum": ["DLT_ATM_RFC1483", "DLT_EN10MB", "DLT_FRELAY", "DLT_C_HDLC", "DLT_PPP_SERIAL"] - } - }, - "additionalProperties": False, - "required": ["capture_file_name"] -} - - -NODE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A node object", - "type": "object", - "properties": { - "compute_id": { - "description": "Compute identifier", - "type": "string" - }, - "project_id": { - "description": "Project UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "node_id": { - "description": "Node UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "template_id": { - "description": "Template UUID from which the node has been created. Read only", - "type": ["null", "string"], - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "node_type": NODE_TYPE_SCHEMA, - "node_directory": { - "description": "Working directory of the node. Read only", - "type": ["null", "string"] - }, - "command_line": { - "description": "Command line use to start the node", - "type": ["null", "string"] - }, - "name": { - "description": "Node name", - "type": "string", - "minLength": 1, - }, - "console": { - "description": "Console TCP port", - "minimum": 1, - "maximum": 65535, - "type": ["integer", "null"] - }, - "console_host": { - "description": "Console host. Warning if the host is 0.0.0.0 or :: (listen on all interfaces) you need to use the same address you use to connect to the controller.", - "type": "string", - "minLength": 1, - }, - "console_type": { - "description": "Console type", - "enum": ["vnc", "telnet", "http", "https", "spice", "spice+agent", "none", None] - }, - "console_auto_start": { - "description": "Automatically start the console when the node has started", - "type": "boolean" - }, - "aux": { - "description": "Auxiliary console TCP port", - "minimum": 1, - "maximum": 65535, - "type": ["integer", "null"] - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["vnc", "telnet", "http", "https", "spice", "spice+agent", "none", None] - }, - "properties": { - "description": "Properties specific to an emulator", - "type": "object" - }, - "status": { - "description": "Status of the node", - "enum": ["stopped", "started", "suspended"] - }, - "label": LABEL_OBJECT_SCHEMA, - "symbol": { - "description": "Symbol of the node", - "type": ["string", "null"], - "minLength": 1 - }, - "width": { - "description": "Width of the node (Read only)", - "type": "integer" - }, - "height": { - "description": "Height of the node (Read only)", - "type": "integer" - }, - "x": { - "description": "X position of the node", - "type": "integer" - }, - "y": { - "description": "Y position of the node", - "type": "integer" - }, - "z": { - "description": "Z position of the node", - "type": "integer" - }, - "locked": { - "description": "Whether the element locked or not", - "type": "boolean" - }, - "port_name_format": { - "description": "Formating for port name {0} will be replace by port number", - "type": "string" - }, - "port_segment_size": { - "description": "Size of the port segment", - "type": "integer", - "minimum": 0 - }, - "first_port_name": { - "description": "Name of the first port", - "type": ["string", "null"], - }, - "custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA, - "ports": { - "description": "List of node ports READ only", - "type": "array", - "items": { - "type": "object", - "description": "A node port", - "properties": { - "name": { - "type": "string", - "description": "Port name", - }, - "short_name": { - "type": "string", - "description": "Short version of port name", - }, - "adapter_number": { - "type": "integer", - "description": "Adapter slot" - }, - "adapter_type": { - "description": "Adapter type", - "type": ["string", "null"], - "minLength": 1, - }, - "port_number": { - "type": "integer", - "description": "Port slot" - }, - "link_type": { - "description": "Type of link", - "enum": ["ethernet", "serial"] - }, - "data_link_types": { - "type": "object", - "description": "Available PCAP types for capture", - "properties": {} - }, - "mac_address": { - "description": "MAC address (if available)", - "type": ["string", "null"], - "minLength": 1, - "pattern": "^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$" - }, - }, - "additionalProperties": False - } - } - }, - "additionalProperties": False, - "required": ["name", "node_type", "compute_id"] -} - -NODE_CREATE_SCHEMA = NODE_OBJECT_SCHEMA -NODE_UPDATE_SCHEMA = copy.deepcopy(NODE_OBJECT_SCHEMA) -del NODE_UPDATE_SCHEMA["required"] - - -NODE_DUPLICATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Duplicate a node", - "type": "object", - "properties": { - "x": { - "description": "X position of the node", - "type": "integer" - }, - "y": { - "description": "Y position of the node", - "type": "integer" - }, - "z": { - "description": "Z position of the node", - "type": "integer" - } - }, - "additionalProperties": False, - "required": ["x", "y"] -} diff --git a/gns3server/endpoints/schemas/nodes.py b/gns3server/schemas/nodes.py similarity index 100% rename from gns3server/endpoints/schemas/nodes.py rename to gns3server/schemas/nodes.py diff --git a/gns3server/schemas/port.py b/gns3server/schemas/port.py deleted file mode 100644 index 26c00913..00000000 --- a/gns3server/schemas/port.py +++ /dev/null @@ -1,115 +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 . - - -PORT_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A port use in the cloud", - "type": "object", - "oneOf": [ - { - "description": "Ethernet interface port", - "properties": { - "name": { - "description": "Port name", - "type": "string", - "minLength": 1, - }, - "port_number": { - "description": "Port number", - "type": "integer", - "minimum": 0 - }, - "type": { - "description": "Port type", - "enum": ["ethernet"] - }, - "interface": { - "description": "Ethernet interface name e.g. eth0", - "type": "string", - "minLength": 1 - }, - }, - "required": ["name", "port_number", "type", "interface"], - "additionalProperties": False - }, - { - "description": "TAP interface port", - "properties": { - "name": { - "description": "Port name", - "type": "string", - "minLength": 1, - }, - "port_number": { - "description": "Port number", - "type": "integer", - "minimum": 0 - }, - "type": { - "description": "Port type", - "enum": ["tap"] - }, - "interface": { - "description": "TAP interface name e.g. tap0", - "type": "string", - "minLength": 1 - }, - }, - "required": ["name", "port_number", "type", "interface"], - "additionalProperties": False - }, - { - "description": "UDP tunnel port", - "properties": { - "name": { - "description": "Port name", - "type": "string", - "minLength": 1, - }, - "port_number": { - "description": "Port number", - "type": "integer", - "minimum": 0 - }, - "type": { - "description": "Port type", - "enum": ["udp"] - }, - "lport": { - "description": "Local UDP tunnel port", - "type": "integer", - "minimum": 1, - "maximum": 65535 - }, - "rhost": { - "description": "Remote UDP tunnel host", - "type": "string", - "minLength": 1 - }, - "rport": { - "description": "Remote UDP tunnel port", - "type": "integer", - "minimum": 1, - "maximum": 65535 - } - }, - "required": ["name", "port_number", "type", "lport", "rhost", "rport"], - "additionalProperties": False - } - ] -} diff --git a/gns3server/schemas/project.py b/gns3server/schemas/project.py deleted file mode 100644 index b65b745b..00000000 --- a/gns3server/schemas/project.py +++ /dev/null @@ -1,329 +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 . - -import copy - -SUPPLIER_OBJECT_SCHEMA = { - "type": ["object", "null"], - "description": "Supplier of the project", - "properties": { - "logo": { - "type": "string", - "description": "Path to the project supplier logo" - }, - "url": { - "type": "string", - "description": "URL to the project supplier site" - } - } -} - - -VARIABLES_OBJECT_SCHEMA = { - "type": ["array", "null"], - "description": "Variables required to run the project", - "items": { - "properties": { - "name": { - "type": "string", - "description": "Variable name", - "minLength": 1 - }, - "value": { - "type": "string", - "description": "Variable value" - } - }, - "required": ["name"] - } -} - - -PROJECT_CREATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to create a new Project instance", - "type": "object", - "properties": { - "name": { - "description": "Project name", - "type": ["string", "null"], - "minLength": 1 - }, - "path": { - "description": "Project directory", - "type": ["string", "null"], - "minLength": 1 - }, - "auto_close": { - "description": "Project auto close", - "type": "boolean" - }, - "project_id": { - "description": "Project UUID", - "type": ["string", "null"], - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "scene_height": { - "type": "integer", - "description": "Height of the drawing area" - }, - "scene_width": { - "type": "integer", - "description": "Width of the drawing area" - }, - "zoom": { - "type": "integer", - "description": "Zoom of the drawing area" - }, - "show_layers": { - "type": "boolean", - "description": "Show layers on the drawing area" - }, - "snap_to_grid": { - "type": "boolean", - "description": "Snap to grid on the drawing area" - }, - "show_grid": { - "type": "boolean", - "description": "Show the grid on the drawing area" - }, - "grid_size": { - "type": "integer", - "description": "Grid size for the drawing area for nodes" - }, - "drawing_grid_size": { - "type": "integer", - "description": "Grid size for the drawing area for drawings" - }, - "show_interface_labels": { - "type": "boolean", - "description": "Show interface labels on the drawing area" - }, - "supplier": SUPPLIER_OBJECT_SCHEMA, - "variables": VARIABLES_OBJECT_SCHEMA - }, - "additionalProperties": False, - "required": ["name"] -} - -# Create a project duplicate schema based on create schema and add "reset_mac_addresses" properties -PROJECT_DUPLICATE_SCHEMA = copy.deepcopy(PROJECT_CREATE_SCHEMA) -PROJECT_DUPLICATE_SCHEMA["description"] = "Request validation to duplicate a Project instance" -PROJECT_DUPLICATE_SCHEMA["properties"].update({"reset_mac_addresses": {"type": "boolean", - "description": "Reset MAC addresses for this project" - }}) - -PROJECT_UPDATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to update a Project instance", - "type": "object", - "properties": { - "name": { - "description": "Project name", - "type": ["string", "null"], - "minLength": 1 - }, - "path": { - "description": "Path of the project on the server (work only with --local)", - "type": ["string", "null"] - }, - "auto_close": { - "description": "Project auto close when client cut off the notifications feed", - "type": "boolean" - }, - "auto_open": { - "description": "Project open when GNS3 start", - "type": "boolean" - }, - "auto_start": { - "description": "Project start when opened", - "type": "boolean" - }, - "scene_height": { - "type": "integer", - "description": "Height of the drawing area" - }, - "scene_width": { - "type": "integer", - "description": "Width of the drawing area" - }, - "zoom": { - "type": "integer", - "description": "Zoom of the drawing area" - }, - "show_layers": { - "type": "boolean", - "description": "Show layers on the drawing area" - }, - "snap_to_grid": { - "type": "boolean", - "description": "Snap to grid on the drawing area" - }, - "show_grid": { - "type": "boolean", - "description": "Show the grid on the drawing area" - }, - "grid_size": { - "type": "integer", - "description": "Grid size for the drawing area for nodes" - }, - "drawing_grid_size": { - "type": "integer", - "description": "Grid size for the drawing area for drawings" - }, - "show_interface_labels": { - "type": "boolean", - "description": "Show interface labels on the drawing area" - }, - "supplier": SUPPLIER_OBJECT_SCHEMA, - "variables": VARIABLES_OBJECT_SCHEMA - }, - "additionalProperties": False, -} - -PROJECT_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Project instance", - "type": "object", - "properties": { - "name": { - "description": "Project name", - "type": ["string", "null"], - "minLength": 1 - }, - "project_id": { - "description": "Project UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "path": { - "description": "Project directory", - "type": ["string", "null"], - "minLength": 1 - }, - "filename": { - "description": "Project filename", - "type": ["string", "null"], - "minLength": 1 - }, - "status": { - "description": "Project status Read only", - "enum": ["opened", "closed"] - }, - "auto_close": { - "description": "Project auto close when client cut off the notifications feed", - "type": "boolean" - }, - "auto_open": { - "description": "Project open when GNS3 start", - "type": "boolean" - }, - "auto_start": { - "description": "Project start when opened", - "type": "boolean" - }, - "scene_height": { - "type": "integer", - "description": "Height of the drawing area" - }, - "scene_width": { - "type": "integer", - "description": "Width of the drawing area" - }, - "zoom": { - "type": "integer", - "description": "Zoom of the drawing area" - }, - "show_layers": { - "type": "boolean", - "description": "Show layers on the drawing area" - }, - "snap_to_grid": { - "type": "boolean", - "description": "Snap to grid on the drawing area" - }, - "show_grid": { - "type": "boolean", - "description": "Show the grid on the drawing area" - }, - "grid_size": { - "type": "integer", - "description": "Grid size for the drawing area for nodes" - }, - "drawing_grid_size": { - "type": "integer", - "description": "Grid size for the drawing area for drawings" - }, - "show_interface_labels": { - "type": "boolean", - "description": "Show interface labels on the drawing area" - }, - "supplier": SUPPLIER_OBJECT_SCHEMA, - "variables": VARIABLES_OBJECT_SCHEMA - }, - "additionalProperties": False, - "required": ["project_id"] -} - -PROJECT_LOAD_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Load a project", - "type": "object", - "properties": { - "path": { - "description": ".gns3 path", - "type": "string", - "minLength": 1 - } - }, - "additionalProperties": False, - "required": ["path"] -} - -PROJECT_LIST_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "List of projects", - "type": "array", - "items": PROJECT_OBJECT_SCHEMA -} - -PROJECT_FILE_LIST_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "List files in the project", - "type": "array", - "items": [ - { - "type": "object", - "properties": { - "path": { - "description": "File path", - "type": ["string"] - }, - "md5sum": { - "description": "MD5 hash of the file", - "type": ["string"] - }, - - }, - } - ], - "additionalProperties": False, -} diff --git a/gns3server/endpoints/schemas/projects.py b/gns3server/schemas/projects.py similarity index 97% rename from gns3server/endpoints/schemas/projects.py rename to gns3server/schemas/projects.py index 9fc6b771..ec0c14b0 100644 --- a/gns3server/endpoints/schemas/projects.py +++ b/gns3server/schemas/projects.py @@ -35,7 +35,7 @@ class ProjectStatus(str, Enum): class Supplier(BaseModel): logo: str = Field(..., description="Path to the project supplier logo") - url: HttpUrl = Field(..., description="URL to the project supplier site") + url: Optional[HttpUrl] = Field(None, description="URL to the project supplier site") class Variable(BaseModel): diff --git a/gns3server/schemas/qemu.py b/gns3server/schemas/qemu.py deleted file mode 100644 index 41a79d50..00000000 --- a/gns3server/schemas/qemu.py +++ /dev/null @@ -1,886 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2014 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 . - -from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA - -QEMU_PLATFORMS = ["aarch64", "alpha", "arm", "cris", "i386", "lm32", "m68k", "microblaze", "microblazeel", "mips", "mips64", "mips64el", "mipsel", "moxie", "or32", "ppc", "ppc64", "ppcemb", "s390x", "sh4", "sh4eb", "sparc", "sparc64", "tricore", "unicore32", "x86_64", "xtensa", "xtensaeb", ""] - - -QEMU_CREATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to create a new QEMU VM instance", - "type": "object", - "properties": { - "node_id": { - "description": "Node UUID", - "oneOf": [ - {"type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"}, - {"type": "integer"} # for legacy projects - ] - }, - "name": { - "description": "QEMU VM instance name", - "type": "string", - "minLength": 1, - }, - "usage": { - "description": "How to use the Qemu VM", - "type": "string", - }, - "linked_clone": { - "description": "Whether the VM is a linked clone or not", - "type": "boolean" - }, - "qemu_path": { - "description": "Path to QEMU", - "type": ["string", "null"], - "minLength": 1, - }, - "platform": { - "description": "Platform to emulate", - "enum": QEMU_PLATFORMS + ["null"] - }, - "console": { - "description": "Console TCP port", - "minimum": 1, - "maximum": 65535, - "type": ["integer", "null"] - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "vnc", "spice", "spice+agent", "none"] - }, - "aux": { - "description": "Auxiliary TCP port", - "minimum": 1, - "maximum": 65535, - "type": ["integer", "null"] - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["telnet", "vnc", "spice", "spice+agent", "none"] - }, - "hda_disk_image": { - "description": "QEMU hda disk image path", - "type": "string", - }, - "hda_disk_interface": { - "description": "QEMU hda interface", - "type": "string", - }, - "hda_disk_image_md5sum": { - "description": "QEMU hda disk image checksum", - "type": ["string", "null"] - }, - "hdb_disk_image": { - "description": "QEMU hdb disk image path", - "type": "string", - }, - "hdb_disk_interface": { - "description": "QEMU hdb interface", - "type": "string", - }, - "hdb_disk_image_md5sum": { - "description": "QEMU hdb disk image checksum", - "type": ["string", "null"], - }, - "hdc_disk_image": { - "description": "QEMU hdc disk image path", - "type": "string", - }, - "hdc_disk_interface": { - "description": "QEMU hdc interface", - "type": "string", - }, - "hdc_disk_image_md5sum": { - "description": "QEMU hdc disk image checksum", - "type": ["string", "null"], - }, - "hdd_disk_image": { - "description": "QEMU hdd disk image path", - "type": "string", - }, - "hdd_disk_interface": { - "description": "QEMU hdd interface", - "type": "string", - }, - "hdd_disk_image_md5sum": { - "description": "QEMU hdd disk image checksum", - "type": ["string", "null"], - }, - "cdrom_image": { - "description": "QEMU cdrom image path", - "type": "string", - }, - "cdrom_image_md5sum": { - "description": "QEMU cdrom image checksum", - "type": ["string", "null"], - }, - "bios_image": { - "description": "QEMU bios image path", - "type": "string", - }, - "bios_image_md5sum": { - "description": "QEMU bios image checksum", - "type": ["string", "null"], - }, - "boot_priority": { - "description": "QEMU boot priority", - "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"] - }, - "ram": { - "description": "Amount of RAM in MB", - "type": ["integer", "null"] - }, - "cpus": { - "description": "Number of vCPUs", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 255, - }, - "maxcpus": { - "description": "Maximum number of hotpluggable vCPUs", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 255, - }, - "adapters": { - "description": "Number of adapters", - "type": ["integer", "null"], - "minimum": 0, - "maximum": 275, - }, - "adapter_type": { - "description": "QEMU adapter type", - "type": ["string", "null"], - "minLength": 1, - }, - "mac_address": { - "description": "QEMU MAC address", - "type": ["string", "null"], - "minLength": 1, - "pattern": "^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$" - }, - "initrd": { - "description": "QEMU initrd path", - "type": "string", - }, - "initrd_md5sum": { - "description": "QEMU initrd path", - "type": ["string", "null"], - }, - "kernel_image": { - "description": "QEMU kernel image path", - "type": "string", - }, - "kernel_image_md5sum": { - "description": "QEMU kernel image checksum", - "type": ["string", "null"], - }, - "kernel_command_line": { - "description": "QEMU kernel command line", - "type": ["string", "null"], - }, - "legacy_networking": { - "description": "Use QEMU legagy networking commands (-net syntax)", - "type": ["boolean", "null"], - }, - "replicate_network_connection_state": { - "description": "Replicate the network connection state for links in Qemu", - "type": ["boolean", "null"], - }, - "create_config_disk": { - "description": "Automatically create a config disk on HDD disk interface (secondary slave)", - "type": ["boolean", "null"], - }, - "on_close": { - "description": "Action to execute on the VM is closed", - "enum": ["power_off", "shutdown_signal", "save_vm_state"], - }, - "cpu_throttling": { - "description": "Percentage of CPU allowed for QEMU", - "minimum": 0, - "maximum": 800, - "type": ["integer", "null"], - }, - "process_priority": { - "description": "Process priority for QEMU", - "enum": ["realtime", - "very high", - "high", - "normal", - "low", - "very low", - "null"] - }, - "options": { - "description": "Additional QEMU options", - "type": ["string", "null"], - }, - "custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA - }, - "additionalProperties": False, - "required": ["name"], -} - -QEMU_UPDATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to update a QEMU VM instance", - "type": "object", - "properties": { - "name": { - "description": "QEMU VM instance name", - "type": ["string", "null"], - "minLength": 1, - }, - "usage": { - "description": "How to use the QEMU VM", - "type": "string", - }, - "qemu_path": { - "description": "Path to QEMU", - "type": ["string", "null"], - "minLength": 1, - }, - "platform": { - "description": "Platform to emulate", - "enum": QEMU_PLATFORMS + ["null"] - }, - "console": { - "description": "Console TCP port", - "minimum": 1, - "maximum": 65535, - "type": ["integer", "null"] - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "vnc", "spice", "spice+agent", "none"] - }, - "aux": { - "description": "Auxiliary TCP port", - "minimum": 1, - "maximum": 65535, - "type": ["integer", "null"] - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["telnet", "vnc", "spice", "spice+agent", "none"] - }, - "linked_clone": { - "description": "Whether the VM is a linked clone or not", - "type": "boolean" - }, - "hda_disk_image": { - "description": "QEMU hda disk image path", - "type": "string", - }, - "hda_disk_interface": { - "description": "QEMU hda interface", - "type": "string", - }, - "hda_disk_image_md5sum": { - "description": "QEMU hda disk image checksum", - "type": ["string", "null"] - }, - "hdb_disk_image": { - "description": "QEMU hdb disk image path", - "type": "string", - }, - "hdb_disk_interface": { - "description": "QEMU hdb interface", - "type": "string", - }, - "hdb_disk_image_md5sum": { - "description": "QEMU hdb disk image checksum", - "type": ["string", "null"], - }, - "hdc_disk_image": { - "description": "QEMU hdc disk image path", - "type": "string", - }, - "hdc_disk_interface": { - "description": "QEMU hdc interface", - "type": "string", - }, - "hdc_disk_image_md5sum": { - "description": "QEMU hdc disk image checksum", - "type": ["string", "null"], - }, - "hdd_disk_image": { - "description": "QEMU hdd disk image path", - "type": "string", - }, - "hdd_disk_interface": { - "description": "QEMU hdd interface", - "type": "string", - }, - "hdd_disk_image_md5sum": { - "description": "QEMU hdd disk image checksum", - "type": ["string", "null"], - }, - "bios_image": { - "description": "QEMU bios image path", - "type": "string", - }, - "bios_image_md5sum": { - "description": "QEMU bios image checksum", - "type": ["string", "null"], - }, - "cdrom_image": { - "description": "QEMU cdrom image path", - "type": "string", - }, - "cdrom_image_md5sum": { - "description": "QEMU cdrom image checksum", - "type": ["string", "null"], - }, - "boot_priority": { - "description": "QEMU boot priority", - "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"] - }, - "ram": { - "description": "Amount of RAM in MB", - "type": ["integer", "null"] - }, - "cpus": { - "description": "Number of vCPUs", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 255, - }, - "maxcpus": { - "description": "Maximum number of hotpluggable vCPUs", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 255, - }, - "adapters": { - "description": "Number of adapters", - "type": ["integer", "null"], - "minimum": 0, - "maximum": 275, - }, - "adapter_type": { - "description": "QEMU adapter type", - "type": ["string", "null"], - "minLength": 1, - }, - "mac_address": { - "description": "QEMU MAC address", - "type": ["string", "null"], - "minLength": 1, - "pattern": "^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$" - }, - "initrd": { - "description": "QEMU initrd path", - "type": "string", - }, - "initrd_md5sum": { - "description": "QEMU initrd path", - "type": ["string", "null"], - }, - "kernel_image": { - "description": "QEMU kernel image path", - "type": "string", - }, - "kernel_image_md5sum": { - "description": "QEMU kernel image checksum", - "type": ["string", "null"], - }, - "kernel_command_line": { - "description": "QEMU kernel command line", - "type": ["string", "null"], - }, - "legacy_networking": { - "description": "Use QEMU legagy networking commands (-net syntax)", - "type": ["boolean", "null"], - }, - "replicate_network_connection_state": { - "description": "Replicate the network connection state for links in Qemu", - "type": ["boolean", "null"], - }, - "create_config_disk": { - "description": "Automatically create a config disk on HDD disk interface (secondary slave)", - "type": ["boolean", "null"], - }, - "on_close": { - "description": "Action to execute on the VM is closed", - "enum": ["power_off", "shutdown_signal", "save_vm_state"], - }, - "cpu_throttling": { - "description": "Percentage of CPU allowed for QEMU", - "minimum": 0, - "maximum": 800, - "type": ["integer", "null"], - }, - "process_priority": { - "description": "Process priority for QEMU", - "enum": ["realtime", - "very high", - "high", - "normal", - "low", - "very low", - "null"] - }, - "options": { - "description": "Additional QEMU options", - "type": ["string", "null"], - }, - "custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA - }, - "additionalProperties": False, -} - -QEMU_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation for a QEMU VM instance", - "type": "object", - "properties": { - "node_id": { - "description": "Node UUID", - "type": "string", - "minLength": 1, - }, - "project_id": { - "description": "Project UUID", - "type": "string", - "minLength": 1, - }, - "name": { - "description": "QEMU VM instance name", - "type": "string", - "minLength": 1, - }, - "status": { - "description": "VM status", - "enum": ["started", "stopped", "suspended"] - }, - "usage": { - "description": "How to use the QEMU VM", - "type": "string", - }, - "qemu_path": { - "description": "Path to QEMU", - "type": "string", - "minLength": 1, - }, - "platform": { - "description": "Platform to emulate", - "enum": QEMU_PLATFORMS - }, - "hda_disk_image": { - "description": "QEMU hda disk image path", - "type": "string", - }, - "hda_disk_interface": { - "description": "QEMU hda interface", - "type": "string", - }, - "hda_disk_image_md5sum": { - "description": "QEMU hda disk image checksum", - "type": ["string", "null"] - }, - "hdb_disk_image": { - "description": "QEMU hdb disk image path", - "type": "string", - }, - "hdb_disk_interface": { - "description": "QEMU hdb interface", - "type": "string", - }, - "hdb_disk_image_md5sum": { - "description": "QEMU hdb disk image checksum", - "type": ["string", "null"], - }, - "hdc_disk_image": { - "description": "QEMU hdc disk image path", - "type": "string", - }, - "hdc_disk_interface": { - "description": "QEMU hdc interface", - "type": "string", - }, - "hdc_disk_image_md5sum": { - "description": "QEMU hdc disk image checksum", - "type": ["string", "null"], - }, - "hdd_disk_image": { - "description": "QEMU hdd disk image path", - "type": "string", - }, - "hdd_disk_interface": { - "description": "QEMU hdd interface", - "type": "string", - }, - "hdd_disk_image_md5sum": { - "description": "QEMU hdd disk image checksum", - "type": ["string", "null"], - }, - "bios_image": { - "description": "QEMU bios image path", - "type": "string", - }, - "bios_image_md5sum": { - "description": "QEMU bios image checksum", - "type": ["string", "null"], - }, - "cdrom_image": { - "description": "QEMU cdrom image path", - "type": "string", - }, - "cdrom_image_md5sum": { - "description": "QEMU cdrom image checksum", - "type": ["string", "null"], - }, - "boot_priority": { - "description": "QEMU boot priority", - "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"] - }, - "node_directory": { - "description": "Path to the VM working directory", - "type": "string" - }, - "ram": { - "description": "Amount of RAM in MB", - "type": "integer" - }, - "cpus": { - "description": "Number of vCPUs", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 255, - }, - "maxcpus": { - "description": "Maximum number of hotpluggable vCPUs", - "type": ["integer", "null"], - "minimum": 1, - "maximum": 255, - }, - "adapters": { - "description": "Number of adapters", - "type": "integer", - "minimum": 0, - "maximum": 275, - }, - "adapter_type": { - "description": "QEMU adapter type", - "type": "string", - "minLength": 1, - }, - "mac_address": { - "description": "QEMU MAC address", - "type": "string", - "minLength": 1, - "pattern": "^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$" - }, - "console": { - "description": "Console TCP port", - "minimum": 1, - "maximum": 65535, - "type": ["integer", "null"] - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "vnc", "spice","spice+agent", "none"] - }, - "aux": { - "description": "Auxiliary TCP port", - "minimum": 1, - "maximum": 65535, - "type": ["integer", "null"] - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["telnet", "vnc", "spice", "spice+agent", "none"] - }, - "initrd": { - "description": "QEMU initrd path", - "type": "string", - }, - "initrd_md5sum": { - "description": "QEMU initrd path", - "type": ["string", "null"], - }, - "kernel_image": { - "description": "QEMU kernel image path", - "type": "string", - }, - "kernel_image_md5sum": { - "description": "QEMU kernel image checksum", - "type": ["string", "null"], - }, - "kernel_command_line": { - "description": "QEMU kernel command line", - "type": "string", - }, - "legacy_networking": { - "description": "Use QEMU legagy networking commands (-net syntax)", - "type": "boolean", - }, - "replicate_network_connection_state": { - "description": "Replicate the network connection state for links in Qemu", - "type": "boolean", - }, - "create_config_disk": { - "description": "Automatically create a config disk on HDD disk interface (secondary slave)", - "type": ["boolean", "null"], - }, - "on_close": { - "description": "Action to execute on the VM is closed", - "enum": ["power_off", "shutdown_signal", "save_vm_state"], - }, - "save_vm_state": { - "description": "Save VM state support", - "type": ["boolean", "null"], - }, - "cpu_throttling": { - "description": "Percentage of CPU allowed for QEMU", - "minimum": 0, - "maximum": 800, - "type": "integer", - }, - "process_priority": { - "description": "Process priority for QEMU", - "enum": ["realtime", - "very high", - "high", - "normal", - "low", - "very low"] - }, - "options": { - "description": "Additional QEMU options", - "type": "string", - }, - "command_line": { - "description": "Last command line used by GNS3 to start QEMU", - "type": "string" - } - }, - "additionalProperties": False, - "required": ["node_id", - "project_id", - "name", - "usage", - "qemu_path", - "platform", - "console_type", - "aux_type", - "hda_disk_image", - "hdb_disk_image", - "hdc_disk_image", - "hdd_disk_image", - "hda_disk_image_md5sum", - "hdb_disk_image_md5sum", - "hdc_disk_image_md5sum", - "hdd_disk_image_md5sum", - "hda_disk_interface", - "hdb_disk_interface", - "hdc_disk_interface", - "hdd_disk_interface", - "cdrom_image", - "cdrom_image_md5sum", - "bios_image", - "bios_image_md5sum", - "boot_priority", - "ram", - "cpus", - "maxcpus", - "adapters", - "adapter_type", - "mac_address", - "console", - "aux", - "initrd", - "kernel_image", - "initrd_md5sum", - "kernel_image_md5sum", - "kernel_command_line", - "legacy_networking", - "replicate_network_connection_state", - "create_config_disk", - "on_close", - "cpu_throttling", - "process_priority", - "options", - "node_directory", - "command_line", - "status"] -} - -QEMU_RESIZE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Resize a disk in a QEMU VM", - "type": "object", - "properties": { - "drive_name": { - "description": "Absolute or relative path of the image", - "enum": ["hda", "hdb", "hdc", "hdd"] - }, - "extend": { - "description": "Number of Megabytes to extend the image", - "type": "integer" - }, - # TODO: support shrink? (could be dangerous) - }, - "required": ["drive_name", "extend"], - "additionalProperties": False -} - -QEMU_BINARY_FILTER_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation for a list of QEMU capabilities", - "properties": { - "archs": { - "description": "Architectures to filter binaries with", - "type": "array", - "items": { - "enum": QEMU_PLATFORMS - } - } - }, - "additionalProperties": False, -} - -QEMU_BINARY_LIST_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation for a list of QEMU binaries", - "type": "array", - "items": { - "$ref": "#/definitions/QemuPath" - }, - "definitions": { - "QemuPath": { - "description": "Qemu path object", - "properties": { - "path": { - "description": "Qemu path", - "type": "string", - }, - "version": { - "description": "Qemu version", - "type": "string", - }, - }, - } - }, - "additionalProperties": False, -} - -QEMU_CAPABILITY_LIST_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation for a list of QEMU capabilities", - "properties": { - "kvm": { - "description": "Architectures that KVM is enabled for", - "type": "array", - "items": { - "enum": QEMU_PLATFORMS - } - } - }, - "additionalProperties": False, -} - -QEMU_IMAGE_CREATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Create a new QEMU image. Options can be specific to a format. Read qemu-img manual for more information", - "type": "object", - "properties": { - "qemu_img": { - "description": "Path to the qemu-img binary", - "type": "string" - }, - "path": { - "description": "Absolute or relative path of the image", - "type": "string" - }, - "format": { - "description": "Image format type", - "enum": ["qcow2", "qcow", "vpc", "vdi", "vmdk", "raw"] - }, - "size": { - "description": "Image size in Megabytes", - "type": "integer" - }, - "preallocation": { - "enum": ["off", "metadata", "falloc", "full"] - }, - "cluster_size": { - "type": "integer" - }, - "refcount_bits": { - "type": "integer" - }, - "lazy_refcounts": { - "enum": ["on", "off"] - }, - "subformat": { - "enum": [ - "dynamic", - "fixed", - "streamOptimized", - "twoGbMaxExtentSparse", - "twoGbMaxExtentFlat", - "monolithicSparse", - "monolithicFlat", - ] - }, - "static": { - "enum": ["on", "off"] - }, - "zeroed_grain": { - "enum": ["on", "off"] - }, - "adapter_type": { - "enum": [ - "ide", - "lsilogic", - "buslogic", - "legacyESX" - ] - } - }, - "required": ["qemu_img", "path", "format", "size"], - "additionalProperties": False -} - -QEMU_IMAGE_UPDATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Update an existing QEMU image", - "type": "object", - "properties": { - "qemu_img": { - "description": "Path to the qemu-img binary", - "type": "string" - }, - "path": { - "description": "Absolute or relative path of the image", - "type": "string" - }, - "extend": { - "description": "Number of Megabytes to extend the image", - "type": "integer" - }, - }, - "required": ["qemu_img", "path"], - "additionalProperties": False -} diff --git a/gns3server/endpoints/schemas/qemu_nodes.py b/gns3server/schemas/qemu_nodes.py similarity index 85% rename from gns3server/endpoints/schemas/qemu_nodes.py rename to gns3server/schemas/qemu_nodes.py index 6fad2b5e..1d42ec07 100644 --- a/gns3server/endpoints/schemas/qemu_nodes.py +++ b/gns3server/schemas/qemu_nodes.py @@ -104,6 +104,54 @@ class QemuProcessPriority(str, Enum): very_low = "very low" +class QemuAdapterType(str, Enum): + """ + Supported Qemu VM adapter types. + """ + + e1000 = "e1000" + e1000_82544gc = "e1000-82544gc" + e1000_82545em = "e1000-82545em" + e1000e = "e1000e" + i82550 = "i82550" + i82551 = "i82551" + i82557a = "i82557a" + i82557b = "i82557b" + i82557c = "i82557c" + i82558a = "i82558a" + i82558b = "i82558b" + i82559a = "i82559a" + i82559b = "i82559b" + i82559c = "i82559c" + i82559er = "i82559er" + i82562 = "i82562" + i82801 = "i82801" + ne2k_pci = "ne2k_pci" + pcnet = "pcnet" + rocker = "rocker" + rtl8139 = "rtl8139" + virtio = "virtio" + virtio_net_pci = "virtio-net-pci" + vmxnet3 = "vmxnet3" + + +class QemuDiskInterfaceType(str, Enum): + """ + Supported Qemu VM disk interface types. + """ + + ide = "ide" + sate = "sata" + nvme = "nvme" + scsi = "scsi" + sd = "sd" + mtd = "mtd" + floppy = "floppy" + pflash = "pflash" + virtio = "virtio" + none = "none" + + class QemuBase(BaseModel): """ Common Qemu node properties. @@ -121,16 +169,16 @@ class QemuBase(BaseModel): aux_type: Optional[QemuConsoleType] = Field(None, description="Auxiliary console type") hda_disk_image: Optional[Path] = Field(None, description="QEMU hda disk image path") hda_disk_image_md5sum: Optional[str] = Field(None, description="QEMU hda disk image checksum") - hda_disk_image_interface: Optional[str] = Field(None, description="QEMU hda interface") + hda_disk_interface: Optional[QemuDiskInterfaceType] = Field(None, description="QEMU hda interface") hdb_disk_image: Optional[Path] = Field(None, description="QEMU hdb disk image path") hdb_disk_image_md5sum: Optional[str] = Field(None, description="QEMU hdb disk image checksum") - hdb_disk_image_interface: Optional[str] = Field(None, description="QEMU hdb interface") + hdb_disk_interface: Optional[QemuDiskInterfaceType] = Field(None, description="QEMU hdb interface") hdc_disk_image: Optional[Path] = Field(None, description="QEMU hdc disk image path") hdc_disk_image_md5sum: Optional[str] = Field(None, description="QEMU hdc disk image checksum") - hdc_disk_image_interface: Optional[str] = Field(None, description="QEMU hdc interface") + hdc_disk_interface: Optional[QemuDiskInterfaceType] = Field(None, description="QEMU hdc interface") hdd_disk_image: Optional[Path] = Field(None, description="QEMU hdd disk image path") hdd_disk_image_md5sum: Optional[str] = Field(None, description="QEMU hdd disk image checksum") - hdd_disk_image_interface: Optional[str] = Field(None, description="QEMU hdd interface") + hdd_disk_interface: Optional[QemuDiskInterfaceType] = Field(None, description="QEMU hdd interface") cdrom_image: Optional[Path] = Field(None, description="QEMU cdrom image path") cdrom_image_md5sum: Optional[str] = Field(None, description="QEMU cdrom image checksum") bios_image: Optional[Path] = Field(None, description="QEMU bios image path") @@ -140,12 +188,12 @@ class QemuBase(BaseModel): kernel_image: Optional[Path] = Field(None, description="QEMU kernel image path") kernel_image_md5sum: Optional[str] = Field(None, description="QEMU kernel image checksum") kernel_command_line: Optional[str] = Field(None, description="QEMU kernel command line") - boot_priotiry: Optional[QemuBootPriority] = Field(None, description="QEMU boot priority") + boot_priority: Optional[QemuBootPriority] = Field(None, description="QEMU boot priority") ram: Optional[int] = Field(None, description="Amount of RAM in MB") cpus: Optional[int] = Field(None, ge=1, le=255, description="Number of vCPUs") maxcpus: Optional[int] = Field(None, ge=1, le=255, description="Maximum number of hotpluggable vCPUs") adapters: Optional[int] = Field(None, ge=0, le=275, description="Number of adapters") - adapter_type: Optional[str] = Field(None, description="QEMU adapter type") + adapter_type: Optional[QemuAdapterType] = Field(None, description="QEMU adapter type") mac_address: Optional[str] = Field(None, description="QEMU MAC address", regex="^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$") legacy_networking: Optional[bool] = Field(None, description="Use QEMU legagy networking commands (-net syntax)") replicate_network_connection_state: Optional[bool] = Field(None, description="Replicate the network connection state for links in Qemu") diff --git a/gns3server/schemas/qemu_template.py b/gns3server/schemas/qemu_template.py deleted file mode 100644 index 213c6e9e..00000000 --- a/gns3server/schemas/qemu_template.py +++ /dev/null @@ -1,234 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES -from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA -from .qemu import QEMU_PLATFORMS - - -QEMU_TEMPLATE_PROPERTIES = { - "qemu_path": { - "description": "Path to QEMU", - "type": "string", - "default": "" - }, - "platform": { - "description": "Platform to emulate", - "enum": QEMU_PLATFORMS, - "default": "i386" - }, - "linked_clone": { - "description": "Whether the VM is a linked clone or not", - "type": "boolean", - "default": True - }, - "ram": { - "description": "Amount of RAM in MB", - "type": "integer", - "default": 256 - }, - "cpus": { - "description": "Number of vCPUs", - "type": "integer", - "minimum": 1, - "maximum": 255, - "default": 1 - }, - "maxcpus": { - "description": "Maximum number of hotpluggable vCPUs", - "type": "integer", - "minimum": 1, - "maximum": 255, - "default": 1 - }, - "adapters": { - "description": "Number of adapters", - "type": "integer", - "minimum": 0, - "maximum": 275, - "default": 1 - }, - "adapter_type": { - "description": "QEMU adapter type", - "type": "string", - "enum": ["e1000", "e1000-82544gc", "e1000-82545em", "e1000e", "i82550", "i82551", "i82557a", "i82557b", "i82557c", "i82558a", - "i82558b", "i82559a", "i82559b", "i82559c", "i82559er", "i82562", "i82801", "ne2k_pci", "pcnet", "rocker", "rtl8139", - "virtio", "virtio-net-pci", "vmxnet3"], - "default": "e1000" - }, - "mac_address": { - "description": "QEMU MAC address", - "type": ["string", "null"], - "anyOf": [ - {"pattern": "^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$"}, - {"pattern": "^$"} - ], - "default": "", - }, - "first_port_name": { - "description": "Optional name of the first networking port example: eth0", - "type": "string", - "default": "" - }, - "port_name_format": { - "description": "Optional formatting of the networking port example: eth{0}", - "type": "string", - "default": "Ethernet{0}" - }, - "port_segment_size": { - "description": "Optional port segment size. A port segment is a block of port. For example Ethernet0/0 Ethernet0/1 is the module 0 with a port segment size of 2", - "type": "integer", - "default": 0 - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "vnc", "spice", "spice+agent", "none"], - "default": "telnet" - }, - "console_auto_start": { - "description": "Automatically start the console when the node has started", - "type": "boolean", - "default": False - }, - "aux_type": { - "description": "Auxiliary console type", - "enum": ["telnet", "vnc", "spice", "spice+agent", "none"], - "default": "none" - }, - "boot_priority": { - "description": "QEMU boot priority", - "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"], - "default": "c" - }, - "hda_disk_image": { - "description": "QEMU hda disk image path", - "type": "string", - "default": "" - }, - "hda_disk_interface": { - "description": "QEMU hda interface", - "enum": ["ide", "sata", "nvme", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"], - "default": "none" - }, - "hdb_disk_image": { - "description": "QEMU hdb disk image path", - "type": "string", - "default": "" - }, - "hdb_disk_interface": { - "description": "QEMU hdb interface", - "enum": ["ide", "sata", "nvme", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"], - "default": "none" - }, - "hdc_disk_image": { - "description": "QEMU hdc disk image path", - "type": "string", - "default": "" - }, - "hdc_disk_interface": { - "description": "QEMU hdc interface", - "enum": ["ide", "sata", "nvme", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"], - "default": "none" - }, - "hdd_disk_image": { - "description": "QEMU hdd disk image path", - "type": "string", - "default": "" - }, - "hdd_disk_interface": { - "description": "QEMU hdd interface", - "enum": ["ide", "sata", "nvme", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"], - "default": "none" - }, - "cdrom_image": { - "description": "QEMU cdrom image path", - "type": "string", - "default": "" - }, - "initrd": { - "description": "QEMU initrd path", - "type": "string", - "default": "" - }, - "kernel_image": { - "description": "QEMU kernel image path", - "type": "string", - "default": "" - }, - "bios_image": { - "description": "QEMU bios image path", - "type": "string", - "default": "" - }, - "kernel_command_line": { - "description": "QEMU kernel command line", - "type": "string", - "default": "" - }, - "legacy_networking": { - "description": "Use QEMU legagy networking commands (-net syntax)", - "type": "boolean", - "default": False - }, - "replicate_network_connection_state": { - "description": "Replicate the network connection state for links in Qemu", - "type": "boolean", - "default": True - }, - "create_config_disk": { - "description": "Automatically create a config disk on HDD disk interface (secondary slave)", - "type": "boolean", - "default": False - }, - "on_close": { - "description": "Action to execute on the VM is closed", - "enum": ["power_off", "shutdown_signal", "save_vm_state"], - "default": "power_off" - }, - "cpu_throttling": { - "description": "Percentage of CPU allowed for QEMU", - "minimum": 0, - "maximum": 800, - "type": "integer", - "default": 0 - }, - "process_priority": { - "description": "Process priority for QEMU", - "enum": ["realtime", "very high", "high", "normal", "low", "very low"], - "default": "normal" - }, - "options": { - "description": "Additional QEMU options", - "type": "string", - "default": "" - }, - "custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA -} - -QEMU_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -QEMU_TEMPLATE_PROPERTIES["category"]["default"] = "guest" -QEMU_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "{name}-{0}" -QEMU_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/qemu_guest.svg" - -QEMU_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A Qemu template object", - "type": "object", - "properties": QEMU_TEMPLATE_PROPERTIES, - "additionalProperties": False -} diff --git a/gns3server/schemas/qemu_templates.py b/gns3server/schemas/qemu_templates.py new file mode 100644 index 00000000..636983bd --- /dev/null +++ b/gns3server/schemas/qemu_templates.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020 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 . + + +from .templates import Category, TemplateBase +from .qemu_nodes import ( + QemuConsoleType, + QemuPlatform, + QemuAdapterType, + QemuOnCloseAction, + QemuBootPriority, + QemuDiskInterfaceType, + QemuProcessPriority, + CustomAdapter +) + +from pathlib import Path +from pydantic import Field +from typing import Optional, List + + +class QemuTemplate(TemplateBase): + + category: Optional[Category] = "guest" + default_name_format: Optional[str] = "{name}-{0}" + symbol: Optional[str] = ":/symbols/qemu_guest.svg" + qemu_path: Optional[Path] = Field("", description="Qemu executable path") + platform: Optional[QemuPlatform] = Field("i386", description="Platform to emulate") + linked_clone: Optional[bool] = Field(True, description="Whether the VM is a linked clone or not") + ram: Optional[int] = Field(256, description="Amount of RAM in MB") + cpus: Optional[int] = Field(1, ge=1, le=255, description="Number of vCPUs") + maxcpus: Optional[int] = Field(1, ge=1, le=255, description="Maximum number of hotpluggable vCPUs") + adapters: Optional[int] = Field(1, ge=0, le=275, description="Number of adapters") + adapter_type: Optional[QemuAdapterType] = Field("e1000", description="QEMU adapter type") + mac_address: Optional[str] = Field("", description="QEMU MAC address", regex="^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$|^$") + first_port_name: Optional[str] = Field("", description="Optional name of the first networking port example: eth0") + port_name_format: Optional[str] = Field("Ethernet{0}", description="Optional formatting of the networking port example: eth{0}") + port_segment_size: Optional[int] = Field(0, description="Optional port segment size. A port segment is a block of port. For example Ethernet0/0 Ethernet0/1 is the module 0 with a port segment size of 2") + console_type: Optional[QemuConsoleType] = Field("telnet", description="Console type") + console_auto_start: Optional[bool] = Field(False, description="Automatically start the console when the node has started") + aux_type: Optional[QemuConsoleType] = Field("none", description="Auxiliary console type") + boot_priority: Optional[QemuBootPriority] = Field("c", description="QEMU boot priority") + hda_disk_image: Optional[Path] = Field("", description="QEMU hda disk image path") + hda_disk_interface: Optional[QemuDiskInterfaceType] = Field("none", description="QEMU hda interface") + hdb_disk_image: Optional[Path] = Field("", description="QEMU hdb disk image path") + hdb_disk_interface: Optional[QemuDiskInterfaceType] = Field("none", description="QEMU hdb interface") + hdc_disk_image: Optional[Path] = Field("", description="QEMU hdc disk image path") + hdc_disk_interface: Optional[QemuDiskInterfaceType] = Field("none", description="QEMU hdc interface") + hdd_disk_image: Optional[Path] = Field("", description="QEMU hdd disk image path") + hdd_disk_interface: Optional[QemuDiskInterfaceType] = Field("none", description="QEMU hdd interface") + cdrom_image: Optional[Path] = Field("", description="QEMU cdrom image path") + initrd: Optional[Path] = Field("", description="QEMU initrd path") + kernel_image: Optional[Path] = Field("", description="QEMU kernel image path") + bios_image: Optional[Path] = Field("", description="QEMU bios image path") + kernel_command_line: Optional[str] = Field("", description="QEMU kernel command line") + legacy_networking: Optional[bool] = Field(False, description="Use QEMU legagy networking commands (-net syntax)") + replicate_network_connection_state: Optional[bool] = Field(True, description="Replicate the network connection state for links in Qemu") + create_config_disk: Optional[bool] = Field(False, description="Automatically create a config disk on HDD disk interface (secondary slave)") + on_close: Optional[QemuOnCloseAction] = Field("power_off", description="Action to execute on the VM is closed") + cpu_throttling: Optional[int] = Field(0, ge=0, le=800, description="Percentage of CPU allowed for QEMU") + process_priority: Optional[QemuProcessPriority] = Field("normal", description="Process priority for QEMU") + options: Optional[str] = Field("", description="Additional QEMU options") + custom_adapters: Optional[List[CustomAdapter]] = Field([], description="Custom adapters") diff --git a/gns3server/schemas/server_statistics.py b/gns3server/schemas/server_statistics.py deleted file mode 100644 index 048799b3..00000000 --- a/gns3server/schemas/server_statistics.py +++ /dev/null @@ -1,82 +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 . - -SERVER_STATISTICS_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "required": ["memory_total", - "memory_free", - "memory_used", - "swap_total", - "swap_free", - "swap_used", - "cpu_usage_percent", - "memory_usage_percent", - "swap_usage_percent", - "disk_usage_percent", - "load_average_percent"], - "additionalProperties": False, - "properties": { - "memory_total": { - "description": "Total physical memory (exclusive swap) in bytes", - "type": "integer", - }, - "memory_free": { - "description": "Free memory in bytes", - "type": "integer", - }, - "memory_used": { - "description": "Memory used in bytes", - "type": "integer", - }, - "swap_total": { - "description": "Total swap memory in bytes", - "type": "integer", - }, - "swap_free": { - "description": "Free swap memory in bytes", - "type": "integer", - }, - "swap_used": { - "description": "Swap memory used in bytes", - "type": "integer", - }, - "cpu_usage_percent": { - "description": "CPU usage in percent", - "type": "integer", - }, - "memory_usage_percent": { - "description": "Memory usage in percent", - "type": "integer", - }, - "swap_usage_percent": { - "description": "Swap usage in percent", - "type": "integer", - }, - "disk_usage_percent": { - "description": "Disk usage in percent", - "type": "integer", - }, - "load_average_percent": { - "description": "Average system load over the last 1, 5 and 15 minutes", - "type": "array", - "items": [{"type": "integer"}], - "minItems": 3, - "maxItems": 3 - }, - } -} diff --git a/gns3server/schemas/snapshot.py b/gns3server/schemas/snapshot.py deleted file mode 100644 index 1c306cd2..00000000 --- a/gns3server/schemas/snapshot.py +++ /dev/null @@ -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 . - - -SNAPSHOT_CREATE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to create a new snapshot", - "type": "object", - "properties": { - "name": { - "description": "Snapshot name", - "minLength": 1 - }, - }, - "additionalProperties": False, - "required": ["name"] -} - -SNAPSHOT_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to update a Project instance", - "type": "object", - "properties": { - "snapshot_id": { - "description": "Snapshot UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "project_id": { - "description": "Project UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "name": { - "description": "Project name", - "type": "string", - "minLength": 1 - }, - "created_at": { - "description": "Date of the snapshot (UTC timestamp)", - "type": "integer" - } - }, - "additionalProperties": False, - "required": ["snapshot_id", "name", "created_at", "project_id"] -} diff --git a/gns3server/endpoints/schemas/snapshots.py b/gns3server/schemas/snapshots.py similarity index 100% rename from gns3server/endpoints/schemas/snapshots.py rename to gns3server/schemas/snapshots.py diff --git a/gns3server/schemas/template.py b/gns3server/schemas/template.py deleted file mode 100644 index 17d3c3d9..00000000 --- a/gns3server/schemas/template.py +++ /dev/null @@ -1,116 +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 . - -import copy - -BASE_TEMPLATE_PROPERTIES = { - "template_id": { - "description": "Template UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "template_type": { - "description": "Type of node", - "enum": ["cloud", "ethernet_hub", "ethernet_switch", "docker", "dynamips", "vpcs", "traceng", - "virtualbox", "vmware", "iou", "qemu"] - }, - "name": { - "description": "Template name", - "type": "string", - "minLength": 1, - }, - "usage": { - "description": "How to use this template", - "type": "string", - "default": "" - }, - "compute_id": { - "description": "Compute identifier", - "type": ["null", "string"] - }, - "default_name_format": { - "description": "Default name format", - "type": "string", - "minLength": 1 - }, - "symbol": { - "description": "Symbol of the template", - "type": "string", - "minLength": 1 - }, - "category": { - "description": "Template category", - "anyOf": [ - {"type": "integer"}, # old category support - {"enum": ["router", "switch", "guest", "firewall"]} - ] - }, - "builtin": { - "description": "Template is builtin", - "type": "boolean" - }, -} - -TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A template object", - "type": "object", - "properties": BASE_TEMPLATE_PROPERTIES, - "required": ["name", "template_type", "template_id", "category", "compute_id", "default_name_format", "symbol", "builtin"] -} - -TEMPLATE_CREATE_SCHEMA = copy.deepcopy(TEMPLATE_OBJECT_SCHEMA) - -# create schema -# these properties are not required to create a template -TEMPLATE_CREATE_SCHEMA["required"].remove("template_id") -TEMPLATE_CREATE_SCHEMA["required"].remove("category") -TEMPLATE_CREATE_SCHEMA["required"].remove("default_name_format") -TEMPLATE_CREATE_SCHEMA["required"].remove("symbol") -TEMPLATE_CREATE_SCHEMA["required"].remove("builtin") - -# update schema -TEMPLATE_UPDATE_SCHEMA = copy.deepcopy(TEMPLATE_OBJECT_SCHEMA) -del TEMPLATE_UPDATE_SCHEMA["required"] - -TEMPLATE_USAGE_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Request validation to use a Template instance", - "type": "object", - "properties": { - "x": { - "description": "X position", - "type": "integer" - }, - "y": { - "description": "Y position", - "type": "integer" - }, - "name": { - "description": "Use this name to create a new node", - "type": ["null", "string"] - }, - "compute_id": { - "description": "If the template don't have a default compute use this compute", - "type": ["null", "string"] - } - }, - "additionalProperties": False, - "required": ["x", "y"] -} diff --git a/gns3server/endpoints/schemas/templates.py b/gns3server/schemas/templates.py similarity index 98% rename from gns3server/endpoints/schemas/templates.py rename to gns3server/schemas/templates.py index 04e23697..af3dcec4 100644 --- a/gns3server/endpoints/schemas/templates.py +++ b/gns3server/schemas/templates.py @@ -45,8 +45,8 @@ class TemplateBase(BaseModel): symbol: Optional[str] = None builtin: Optional[bool] = None template_type: Optional[NodeType] = None - usage: Optional[str] = None compute_id: Optional[str] = None + usage: Optional[str] = "" class Config: extra = "allow" diff --git a/gns3server/schemas/topology.py b/gns3server/schemas/topology.py index 21d5e6da..9cf882dc 100644 --- a/gns3server/schemas/topology.py +++ b/gns3server/schemas/topology.py @@ -19,136 +19,66 @@ # This file contains the validation for checking a .gns3 file # -from gns3server.schemas.compute import COMPUTE_OBJECT_SCHEMA -from gns3server.schemas.drawing import DRAWING_OBJECT_SCHEMA -from gns3server.schemas.link import LINK_OBJECT_SCHEMA -from gns3server.schemas.node import NODE_OBJECT_SCHEMA -from gns3server.schemas.project import VARIABLES_OBJECT_SCHEMA -from gns3server.schemas.project import SUPPLIER_OBJECT_SCHEMA +from .computes import Compute +from .drawings import Drawing +from .links import Link +from .nodes import Node + +from .projects import ( + Supplier, + Variable +) + +from pydantic import BaseModel, Field +from typing import Optional, List +from enum import Enum +from uuid import UUID -TOPOLOGY_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "The topology", - "type": "object", - "properties": { - "project_id": { - "description": "Project UUID", - "type": "string", - "minLength": 36, - "maxLength": 36, - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "type": { - "description": "Type of file. It's always topology", - "enum": ["topology"] - }, - "auto_start": { - "description": "Start the topology when opened", - "type": "boolean" - }, - "auto_close": { - "description": "Close the topology when no client is connected", - "type": "boolean" - }, - "auto_open": { - "description": "Open the topology with GNS3", - "type": "boolean" - }, - "revision": { - "description": "Version of the .gns3 specification.", - "type": "integer" - }, - "version": { - "description": "Version of the GNS3 software which have update the file for the last time", - "type": "string" - }, - "name": { - "type": "string", - "description": "Name of the project" - }, - "scene_height": { - "type": "integer", - "description": "Height of the drawing area" - }, - "scene_width": { - "type": "integer", - "description": "Width of the drawing area" - }, - "zoom": { - "type": "integer", - "description": "Zoom of the drawing area" - }, - "show_layers": { - "type": "boolean", - "description": "Show layers on the drawing area" - }, - "snap_to_grid": { - "type": "boolean", - "description": "Snap to grid on the drawing area" - }, - "show_grid": { - "type": "boolean", - "description": "Show the grid on the drawing area" - }, - "grid_size": { - "type": "integer", - "description": "Grid size for the drawing area for nodes" - }, - "drawing_grid_size": { - "type": "integer", - "description": "Grid size for the drawing area for drawings" - }, - "show_interface_labels": { - "type": "boolean", - "description": "Show interface labels on the drawing area" - }, - "supplier": SUPPLIER_OBJECT_SCHEMA, - "variables": VARIABLES_OBJECT_SCHEMA, - "topology": { - "description": "The topology content", - "type": "object", - "properties": { - "computes": { - "description": "Computes servers", - "type": "array", - "items": COMPUTE_OBJECT_SCHEMA - }, - "drawings": { - "description": "Drawings elements", - "type": "array", - "items": DRAWING_OBJECT_SCHEMA - }, - "links": { - "description": "Link elements", - "type": "array", - "items": LINK_OBJECT_SCHEMA - }, - "nodes": { - "description": "Nodes elements", - "type": "array", - "items": NODE_OBJECT_SCHEMA - } - }, - "required": ["nodes", "links", "drawings", "computes"], - "additionalProperties": False - } - }, - "required": [ - "project_id", "type", "revision", "version", "name", "topology" - ], - "additionalProperties": False -} +class TopologyType(str, Enum): + + topology = "topology" + + +class TopologyContent(BaseModel): + + computes: List[Compute] = Field(..., description="List of computes") + drawings: List[Drawing] = Field(..., description="List of drawings") + links: List[Link] = Field(..., description="List of links") + nodes: List[Node] = Field(..., description="List of nodes") + + +class Topology(BaseModel): + + project_id: UUID = Field(..., description="Project UUID") + type: TopologyType = Field(..., description="Type of file. It's always topology") + revision: int = Field(..., description="Version of the .gns3 specification") + version: str = Field(..., description="Version of the GNS3 software which have update the file for the last time") + name: str = Field(..., description="Name of the project") + topology: TopologyContent = Field(..., description="Topology content") + auto_start: Optional[bool] = Field(None, description="Start the topology when opened") + auto_close: Optional[bool] = Field(None, description="Close the topology when no client is connected") + scene_height: Optional[int] = Field(None, description="Height of the drawing area") + scene_width: Optional[int] = Field(None, description="Width of the drawing area") + zoom: Optional[int] = Field(None, description="Zoom of the drawing area") + show_layers: Optional[bool] = Field(None, description="Show layers on the drawing area") + snap_to_grid: Optional[bool] = Field(None, description="Snap to grid on the drawing area") + show_grid: Optional[bool] = Field(None, description="Show the grid on the drawing area") + grid_size: Optional[int] = Field(None, description="Grid size for the drawing area for nodes") + drawing_grid_size: Optional[int] = Field(None, description="Grid size for the drawing area for drawings") + show_interface_labels: Optional[bool] = Field(None, description="Show interface labels on the drawing area") + supplier: Optional[Supplier] = Field(None, description="Supplier of the project") + variables: Optional[List[Variable]] = Field(None, description="Variables required to run the project") def main(): - import jsonschema + import json import sys with open(sys.argv[1]) as f: data = json.load(f) - jsonschema.validate(data, TOPOLOGY_SCHEMA) + Topology.parse_obj(data) if __name__ == '__main__': diff --git a/gns3server/schemas/traceng_template.py b/gns3server/schemas/traceng_template.py deleted file mode 100644 index 5c574685..00000000 --- a/gns3server/schemas/traceng_template.py +++ /dev/null @@ -1,51 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES - - -TRACENG_TEMPLATE_PROPERTIES = { - "ip_address": { - "description": "Source IP address for tracing", - "type": ["string"], - "minLength": 1 - }, - "default_destination": { - "description": "Default destination IP address or hostname for tracing", - "type": ["string"], - "minLength": 1 - }, - "console_type": { - "description": "Console type", - "enum": ["none"], - "default": "none" - }, -} - -TRACENG_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -TRACENG_TEMPLATE_PROPERTIES["category"]["default"] = "guest" -TRACENG_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "TraceNG{0}" -TRACENG_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/traceng.svg" - -TRACENG_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A TraceNG template object", - "type": "object", - "properties": TRACENG_TEMPLATE_PROPERTIES, - "additionalProperties": False -} diff --git a/gns3server/schemas/version.py b/gns3server/schemas/version.py index ac739dd5..cb92d953 100644 --- a/gns3server/schemas/version.py +++ b/gns3server/schemas/version.py @@ -15,19 +15,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -VERSION_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - 'required': ['version'], - "additionalProperties": False, - "properties": { - "version": { - "description": "Version number", - "type": "string", - }, - "local": { - "description": "Whether this is a local server or not", - "type": "boolean", - } - } -} +from pydantic import BaseModel, Field +from typing import Optional + + +class Version(BaseModel): + + version: str = Field(..., description="Version number") + local: Optional[bool] = Field(None, description="Whether this is a local server or not") diff --git a/gns3server/endpoints/schemas/virtualbox_nodes.py b/gns3server/schemas/virtualbox_nodes.py similarity index 84% rename from gns3server/endpoints/schemas/virtualbox_nodes.py rename to gns3server/schemas/virtualbox_nodes.py index 804f3825..56f26565 100644 --- a/gns3server/endpoints/schemas/virtualbox_nodes.py +++ b/gns3server/schemas/virtualbox_nodes.py @@ -42,6 +42,16 @@ class VirtualBoxOnCloseAction(str, Enum): save_vm_state = "save_vm_state" +class VirtualBoxAdapterType(str, Enum): + + pcnet_pci_ii = "PCnet-PCI II (Am79C970A)", + pcnet_fast_iii = "PCNet-FAST III (Am79C973)", + intel_pro_1000_mt_desktop = "Intel PRO/1000 MT Desktop (82540EM)", + intel_pro_1000_t_server = "Intel PRO/1000 T Server (82543GC)", + intel_pro_1000_mt_server = "Intel PRO/1000 MT Server (82545EM)", + paravirtualized_network = "Paravirtualized Network (virtio-net)" + + class VirtualBoxBase(BaseModel): """ Common VirtualBox node properties. @@ -54,14 +64,14 @@ class VirtualBoxBase(BaseModel): usage: Optional[str] = Field(None, description="How to use the node") # 36 adapters is the maximum given by the ICH9 chipset in VirtualBox adapters: Optional[int] = Field(None, ge=0, le=36, description="Number of adapters") - adapter_type: Optional[str] = Field(None, description="VirtualBox adapter type") + adapter_type: Optional[VirtualBoxAdapterType] = Field(None, description="VirtualBox adapter type") use_any_adapter: Optional[bool] = Field(None, description="Allow GNS3 to use any VirtualBox adapter") console: Optional[int] = Field(None, gt=0, le=65535, description="Console TCP port") console_type: Optional[VirtualBoxConsoleType] = Field(None, description="Console type") ram: Optional[int] = Field(None, ge=0, le=65535, description="Amount of RAM in MB") headless: Optional[bool] = Field(None, description="Headless mode") on_close: Optional[VirtualBoxOnCloseAction] = Field(None, description="Action to execute on the VM is closed") - custom_adapters: Optional[List[CustomAdapter]] = Field(None, description="Custom adpaters") + custom_adapters: Optional[List[CustomAdapter]] = Field(None, description="Custom adapters") class VirtualBoxCreate(VirtualBoxBase): diff --git a/gns3server/schemas/virtualbox_template.py b/gns3server/schemas/virtualbox_template.py deleted file mode 100644 index 36ff47c2..00000000 --- a/gns3server/schemas/virtualbox_template.py +++ /dev/null @@ -1,113 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES -from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA - - -VIRTUALBOX_TEMPLATE_PROPERTIES = { - "vmname": { - "description": "VirtualBox VM name (in VirtualBox itself)", - "type": "string", - "minLength": 1, - }, - "ram": { - "description": "Amount of RAM", - "minimum": 0, - "maximum": 65535, - "type": "integer", - "default": 256 - }, - "linked_clone": { - "description": "Whether the VM is a linked clone or not", - "type": "boolean", - "default": False - }, - "adapters": { - "description": "Number of adapters", - "type": "integer", - "minimum": 0, - "maximum": 36, # maximum given by the ICH9 chipset in VirtualBox - "default": 1 - }, - "use_any_adapter": { - "description": "Allow GNS3 to use any VirtualBox adapter", - "type": "boolean", - "default": False - }, - "adapter_type": { - "description": "VirtualBox adapter type", - "enum": ["PCnet-PCI II (Am79C970A)", - "PCNet-FAST III (Am79C973)", - "Intel PRO/1000 MT Desktop (82540EM)", - "Intel PRO/1000 T Server (82543GC)", - "Intel PRO/1000 MT Server (82545EM)", - "Paravirtualized Network (virtio-net)"], - "default": "Intel PRO/1000 MT Desktop (82540EM)" - }, - "first_port_name": { - "description": "Optional name of the first networking port example: eth0", - "type": "string", - "default": "" - }, - "port_name_format": { - "description": "Optional formatting of the networking port example: eth{0}", - "type": "string", - "default": "Ethernet{0}" - }, - "port_segment_size": { - "description": "Optional port segment size. A port segment is a block of port. For example Ethernet0/0 Ethernet0/1 is the module 0 with a port segment size of 2", - "type": "integer", - "default": 0 - }, - "headless": { - "description": "Headless mode", - "type": "boolean", - "default": False - }, - "on_close": { - "description": "Action to execute on the VM is closed", - "enum": ["power_off", "shutdown_signal", "save_vm_state"], - "default": "power_off" - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "none"], - "default": "none" - }, - "console_auto_start": { - "description": "Automatically start the console when the node has started", - "type": "boolean", - "default": False - }, - "custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA -} - -VIRTUALBOX_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -VIRTUALBOX_TEMPLATE_PROPERTIES["category"]["default"] = "guest" -VIRTUALBOX_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "{name}-{0}" -VIRTUALBOX_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/vbox_guest.svg" - -VIRTUALBOX_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A VirtualBox template object", - "type": "object", - "properties": VIRTUALBOX_TEMPLATE_PROPERTIES, - "required": ["vmname"], - "additionalProperties": False -} diff --git a/gns3server/schemas/virtualbox_templates.py b/gns3server/schemas/virtualbox_templates.py new file mode 100644 index 00000000..1f0af97e --- /dev/null +++ b/gns3server/schemas/virtualbox_templates.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020 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 . + +from .templates import Category, TemplateBase +from .virtualbox_nodes import ( + VirtualBoxConsoleType, + VirtualBoxAdapterType, + VirtualBoxOnCloseAction, + CustomAdapter +) + +from pydantic import Field +from typing import Optional, List + + +class VirtualBoxTemplate(TemplateBase): + + category: Optional[Category] = "guest" + default_name_format: Optional[str] = "{name}-{0}" + symbol: Optional[str] = ":/symbols/vbox_guest.svg" + vmname: str = Field(..., description="VirtualBox VM name (in VirtualBox itself)") + ram: Optional[int] = Field(256, gt=0, description="Amount of RAM in MB") + linked_clone: Optional[bool] = Field(False, description="Whether the VM is a linked clone or not") + adapters: Optional[int] = Field(1, ge=0, le=36, description="Number of adapters") # 36 is the maximum given by the ICH9 chipset in VirtualBox + use_any_adapter: Optional[bool] = Field(False, description="Allow GNS3 to use any VirtualBox adapter") + adapter_type: Optional[VirtualBoxAdapterType] = Field("Intel PRO/1000 MT Desktop (82540EM)", description="VirtualBox adapter type") + first_port_name: Optional[str] = Field("", description="Optional name of the first networking port example: eth0") + port_name_format: Optional[str] = Field("Ethernet{0}", description="Optional formatting of the networking port example: eth{0}") + port_segment_size: Optional[int] = Field(0, description="Optional port segment size. A port segment is a block of port. For example Ethernet0/0 Ethernet0/1 is the module 0 with a port segment size of 2") + headless: Optional[bool] = Field(False, description="Headless mode") + on_close: Optional[VirtualBoxOnCloseAction] = Field("power_off", description="Action to execute on the VM is closed") + console_type: Optional[VirtualBoxConsoleType] = Field("none", description="Console type") + console_auto_start: Optional[bool] = Field(False, description="Automatically start the console when the node has started") + custom_adapters: Optional[List[CustomAdapter]] = Field([], description="Custom adapters") diff --git a/gns3server/endpoints/schemas/vmware_nodes.py b/gns3server/schemas/vmware_nodes.py similarity index 88% rename from gns3server/endpoints/schemas/vmware_nodes.py rename to gns3server/schemas/vmware_nodes.py index ca5aef75..fadb6701 100644 --- a/gns3server/endpoints/schemas/vmware_nodes.py +++ b/gns3server/schemas/vmware_nodes.py @@ -43,6 +43,21 @@ class VMwareOnCloseAction(str, Enum): save_vm_state = "save_vm_state" +class VMwareAdapterType(str, Enum): + """ + Supported VMware VM adapter types. + """ + + default = "default" + e1000 = "e1000" + e1000e = "e1000e" + flexible = "flexible" + vlance = "vlance" + vmxnet = "vmxnet" + vmxnet2 = "vmxnet2" + vmxnet3 = "vmxnet3" + + class VMwareBase(BaseModel): """ Common VMware node properties. @@ -59,7 +74,7 @@ class VMwareBase(BaseModel): on_close: Optional[VMwareOnCloseAction] = Field(None, description="Action to execute on the VM is closed") # 10 adapters is the maximum supported by VMware VMs. adapters: Optional[int] = Field(None, ge=0, le=10, description="Number of adapters") - adapter_type: Optional[str] = Field(None, description="VMware adapter type") + adapter_type: Optional[VMwareAdapterType] = Field(None, description="VMware adapter type") use_any_adapter: Optional[bool] = Field(None, description="Allow GNS3 to use any VMware adapter") custom_adapters: Optional[List[CustomAdapter]] = Field(None, description="Custom adpaters") diff --git a/gns3server/schemas/vmware_template.py b/gns3server/schemas/vmware_template.py deleted file mode 100644 index c4c6ac88..00000000 --- a/gns3server/schemas/vmware_template.py +++ /dev/null @@ -1,101 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES -from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA - - -VMWARE_TEMPLATE_PROPERTIES = { - "vmx_path": { - "description": "Path to the vmx file", - "type": "string", - "minLength": 1, - }, - "linked_clone": { - "description": "Whether the VM is a linked clone or not", - "type": "boolean", - "default": False - }, - "first_port_name": { - "description": "Optional name of the first networking port example: eth0", - "type": "string", - "default": "" - }, - "port_name_format": { - "description": "Optional formatting of the networking port example: eth{0}", - "type": "string", - "default": "Ethernet{0}" - }, - "port_segment_size": { - "description": "Optional port segment size. A port segment is a block of port. For example Ethernet0/0 Ethernet0/1 is the module 0 with a port segment size of 2", - "type": "integer", - "default": 0 - }, - "adapters": { - "description": "Number of adapters", - "type": "integer", - "minimum": 0, - "maximum": 10, # maximum adapters support by VMware VMs, - "default": 1 - }, - "adapter_type": { - "description": "VMware adapter type", - "enum": ["default", "e1000", "e1000e", "flexible", "vlance", "vmxnet", "vmxnet2", "vmxnet3"], - "default": "e1000" - }, - "use_any_adapter": { - "description": "Allow GNS3 to use any VMware adapter", - "type": "boolean", - "default": False - }, - "headless": { - "description": "Headless mode", - "type": "boolean", - "default": False - }, - "on_close": { - "description": "Action to execute on the VM is closed", - "enum": ["power_off", "shutdown_signal", "save_vm_state"], - "default": "power_off" - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "none"], - "default": "none" - }, - "console_auto_start": { - "description": "Automatically start the console when the node has started", - "type": "boolean", - "default": False - }, - "custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA -} - -VMWARE_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -VMWARE_TEMPLATE_PROPERTIES["category"]["default"] = "guest" -VMWARE_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "{name}-{0}" -VMWARE_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/vmware_guest.svg" - -VMWARE_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A VMware template object", - "type": "object", - "properties": VMWARE_TEMPLATE_PROPERTIES, - "required": ["vmx_path"], - "additionalProperties": False -} diff --git a/gns3server/schemas/vmware_templates.py b/gns3server/schemas/vmware_templates.py new file mode 100644 index 00000000..6b85000f --- /dev/null +++ b/gns3server/schemas/vmware_templates.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020 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 . + + +from .templates import Category, TemplateBase +from .vmware_nodes import ( + VMwareConsoleType, + VMwareAdapterType, + VMwareOnCloseAction, + CustomAdapter +) + +from pathlib import Path +from pydantic import Field +from typing import Optional, List + + +class VMwareTemplate(TemplateBase): + + category: Optional[Category] = "guest" + default_name_format: Optional[str] = "{name}-{0}" + symbol: Optional[str] = ":/symbols/vmware_guest.svg" + vmx_path: Path = Field(..., description="Path to the vmx file") + linked_clone: Optional[bool] = Field(False, description="Whether the VM is a linked clone or not") + first_port_name: Optional[str] = Field("", description="Optional name of the first networking port example: eth0") + port_name_format: Optional[str] = Field("Ethernet{0}", description="Optional formatting of the networking port example: eth{0}") + port_segment_size: Optional[int] = Field(0, description="Optional port segment size. A port segment is a block of port. For example Ethernet0/0 Ethernet0/1 is the module 0 with a port segment size of 2") + adapters: Optional[int] = Field(1, ge=0, le=10, description="Number of adapters") # 10 is the maximum adapters support by VMware VMs + adapter_type: Optional[VMwareAdapterType] = Field("e1000", description="VMware adapter type") + use_any_adapter: Optional[bool] = Field(False, description="Allow GNS3 to use any VMware adapter") + headless: Optional[bool] = Field(False, description="Headless mode") + on_close: Optional[VMwareOnCloseAction] = Field("power_off", description="Action to execute on the VM is closed") + console_type: Optional[VMwareConsoleType] = Field("none", description="Console type") + console_auto_start: Optional[bool] = Field(False, description="Automatically start the console when the node has started") + custom_adapters: Optional[List[CustomAdapter]] = Field([], description="Custom adapters") diff --git a/gns3server/endpoints/schemas/vpcs_nodes.py b/gns3server/schemas/vpcs_nodes.py similarity index 94% rename from gns3server/endpoints/schemas/vpcs_nodes.py rename to gns3server/schemas/vpcs_nodes.py index 4698413e..a09d40b3 100644 --- a/gns3server/endpoints/schemas/vpcs_nodes.py +++ b/gns3server/schemas/vpcs_nodes.py @@ -23,7 +23,7 @@ from uuid import UUID from .nodes import NodeStatus, CustomAdapter -class VPCSConsoleType(str, Enum): +class ConsoleType(str, Enum): """ Supported console types. """ @@ -41,7 +41,7 @@ class VPCSBase(BaseModel): node_id: Optional[UUID] usage: Optional[str] = Field(None, description="How to use the node") console: Optional[int] = Field(None, gt=0, le=65535, description="Console TCP port") - console_type: Optional[VPCSConsoleType] = Field(None, description="Console type") + console_type: Optional[ConsoleType] = Field(None, description="Console type") startup_script: Optional[str] = Field(None, description="Content of the VPCS startup script") diff --git a/gns3server/schemas/vpcs_template.py b/gns3server/schemas/vpcs_template.py deleted file mode 100644 index e0726b24..00000000 --- a/gns3server/schemas/vpcs_template.py +++ /dev/null @@ -1,52 +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 . - -import copy -from .template import BASE_TEMPLATE_PROPERTIES - - -VPCS_TEMPLATE_PROPERTIES = { - "base_script_file": { - "description": "Script file", - "type": "string", - "minLength": 1, - "default": "vpcs_base_config.txt" - }, - "console_type": { - "description": "Console type", - "enum": ["telnet", "none"], - "default": "telnet" - }, - "console_auto_start": { - "description": "Automatically start the console when the node has started", - "type": "boolean", - "default": False - }, -} - -VPCS_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) -VPCS_TEMPLATE_PROPERTIES["category"]["default"] = "guest" -VPCS_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "PC{0}" -VPCS_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/vpcs_guest.svg" - -VPCS_TEMPLATE_OBJECT_SCHEMA = { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "A VPCS template object", - "type": "object", - "properties": VPCS_TEMPLATE_PROPERTIES, - "additionalProperties": False -} diff --git a/gns3server/endpoints/schemas/vpcs_templates.py b/gns3server/schemas/vpcs_templates.py similarity index 66% rename from gns3server/endpoints/schemas/vpcs_templates.py rename to gns3server/schemas/vpcs_templates.py index 6ee5f6a4..ba16f12d 100644 --- a/gns3server/endpoints/schemas/vpcs_templates.py +++ b/gns3server/schemas/vpcs_templates.py @@ -17,52 +17,17 @@ from .templates import Category, TemplateBase +from .vpcs_nodes import ConsoleType from pydantic import Field -from typing import Optional, Union -from enum import Enum - -from .nodes import NodeType +from typing import Optional -class ConsoleType(str, Enum): - """ - Supported console types for VPCS nodes - """ - - none = "none" - telnet = "telnet" - - -class VPCSTemplateBase(TemplateBase): +class VPCSTemplate(TemplateBase): category: Optional[Category] = "guest" default_name_format: Optional[str] = "PC{0}" symbol: Optional[str] = ":/symbols/vpcs_guest.svg" - base_script_file: Optional[str] = Field("vpcs_base_config.txt", description="Script file") console_type: Optional[ConsoleType] = Field("telnet", description="Console type") console_auto_start: Optional[bool] = Field(False, description="Automatically start the console when the node has started") - - -class VPCSTemplateCreate(VPCSTemplateBase): - - name: str - template_type: NodeType - compute_id: str - - -class VPCSTemplateUpdate(VPCSTemplateBase): - - pass - - -class VPCSTemplate(VPCSTemplateBase): - - template_id: str - name: str - category: Category - symbol: str - builtin: bool - template_type: NodeType - compute_id: Union[str, None] diff --git a/gns3server/templates/compute.html b/gns3server/templates/compute.html index dd563d26..2ef05621 100644 --- a/gns3server/templates/compute.html +++ b/gns3server/templates/compute.html @@ -2,7 +2,7 @@ {% block head %}