1
0
mirror of https://github.com/GNS3/gns3-server synced 2025-01-12 09:00:57 +00:00

Merge pull request #1458 from GNS3/appliance-default-settings

Apply default settings when adding an appliance via API. Fixes #1456
This commit is contained in:
Jeremy Grossmann 2018-11-17 19:39:34 +07:00 committed by GitHub
commit 82140c082c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 2281 additions and 873 deletions

View File

@ -23,6 +23,7 @@ import socket
import shutil import shutil
import asyncio import asyncio
import aiohttp import aiohttp
import jsonschema
from ..config import Config from ..config import Config
from .project import Project from .project import Project
@ -144,10 +145,9 @@ class Controller:
appliance_id = settings.setdefault("appliance_id", str(uuid.uuid4())) appliance_id = settings.setdefault("appliance_id", str(uuid.uuid4()))
try: try:
appliance = Appliance(appliance_id, settings) appliance = Appliance(appliance_id, settings)
appliance.__json__() # Check if loaded without error except jsonschema.ValidationError as e:
except KeyError as e: message = "JSON schema error adding appliance with JSON data '{}': {}".format(settings, e.message)
# appliance settings is not complete raise aiohttp.web.HTTPBadRequest(text=message)
raise aiohttp.web.HTTPConflict(text="Cannot create new appliance: key '{}' is missing for appliance ID '{}'".format(e, appliance_id))
self._appliances[appliance.id] = appliance self._appliances[appliance.id] = appliance
self.save() self.save()
self.notification.controller_emit("appliance.created", appliance.__json__()) self.notification.controller_emit("appliance.created", appliance.__json__())
@ -327,11 +327,10 @@ class Controller:
for appliance_settings in controller_settings["appliances"]: for appliance_settings in controller_settings["appliances"]:
try: try:
appliance = Appliance(appliance_settings["appliance_id"], appliance_settings) appliance = Appliance(appliance_settings["appliance_id"], appliance_settings)
appliance.__json__() # Check if loaded without error
self._appliances[appliance.id] = appliance self._appliances[appliance.id] = appliance
except KeyError as e: except jsonschema.ValidationError as e:
# appliance data is not complete (missing name or type) message = "Cannot load appliance with JSON data '{}': {}".format(appliance_settings, e.message)
log.warning("Cannot load appliance template {} ('{}'): missing key {}".format(appliance_settings["appliance_id"], appliance_settings.get("name", "unknown"), e)) log.warning(message)
continue continue
# load GNS3 VM settings # load GNS3 VM settings

View File

@ -17,6 +17,56 @@
import copy import copy
import uuid import uuid
import json
import jsonschema
from gns3server.schemas.cloud_appliance import CLOUD_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.ethernet_switch_appliance import ETHERNET_SWITCH_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.ethernet_hub_appliance import ETHERNET_HUB_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.docker_appliance import DOCKER_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.vpcs_appliance import VPCS_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.traceng_appliance import TRACENG_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.virtualbox_appliance import VIRTUALBOX_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.vmware_appliance import VMWARE_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.iou_appliance import IOU_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.qemu_appliance import QEMU_APPLIANCE_OBJECT_SCHEMA
from gns3server.schemas.dynamips_appliance import (
DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
C7200_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
C3745_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
C3725_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
C3600_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
C2691_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
C2600_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
C1700_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA
)
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 = { ID_TO_CATEGORY = {
3: "firewall", 3: "firewall",
@ -25,6 +75,30 @@ ID_TO_CATEGORY = {
0: "router" 0: "router"
} }
APPLIANCE_TYPE_TO_SHEMA = {
"cloud": CLOUD_APPLIANCE_OBJECT_SCHEMA,
"ethernet_hub": ETHERNET_HUB_APPLIANCE_OBJECT_SCHEMA,
"ethernet_switch": ETHERNET_SWITCH_APPLIANCE_OBJECT_SCHEMA,
"docker": DOCKER_APPLIANCE_OBJECT_SCHEMA,
"dynamips": DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
"vpcs": VPCS_APPLIANCE_OBJECT_SCHEMA,
"traceng": TRACENG_APPLIANCE_OBJECT_SCHEMA,
"virtualbox": VIRTUALBOX_APPLIANCE_OBJECT_SCHEMA,
"vmware": VMWARE_APPLIANCE_OBJECT_SCHEMA,
"iou": IOU_APPLIANCE_OBJECT_SCHEMA,
"qemu": QEMU_APPLIANCE_OBJECT_SCHEMA
}
DYNAMIPS_PLATFORM_TO_SHEMA = {
"c7200": C7200_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
"c3745": C3745_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
"c3725": C3725_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
"c3600": C3600_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
"c2691": C2691_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
"c2600": C2600_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA,
"c1700": C1700_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA
}
class Appliance: class Appliance:
@ -66,6 +140,13 @@ class Appliance:
self._builtin = builtin self._builtin = builtin
if builtin is False:
self.validate_and_apply_defaults(APPLIANCE_TYPE_TO_SHEMA[self.appliance_type])
if self.appliance_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"]])
@property @property
def id(self): def id(self):
return self._id return self._id
@ -102,6 +183,17 @@ class Appliance:
controller.notification.controller_emit("appliance.updated", self.__json__()) controller.notification.controller_emit("appliance.updated", self.__json__())
controller.save() 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): def __json__(self):
""" """
Appliance settings. Appliance settings.
@ -109,8 +201,6 @@ class Appliance:
settings = self._settings settings = self._settings
settings.update({"appliance_id": self._id, settings.update({"appliance_id": self._id,
"default_name_format": settings.get("default_name_format", "{name}-{0}"),
"symbol": settings.get("symbol", ":/symbols/computer.svg"),
"builtin": self.builtin}) "builtin": self.builtin})
if not self.builtin: if not self.builtin:

View File

@ -16,24 +16,39 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy import copy
from .dynamips_vm import DYNAMIPS_ADAPTERS, DYNAMIPS_WICS
from .qemu import QEMU_PLATFORMS
from .port import PORT_OBJECT_SCHEMA
from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA
BASE_APPLIANCE_PROPERTIES = { BASE_APPLIANCE_PROPERTIES = {
"appliance_id": { "appliance_id": {
"description": "Appliance UUID from which the node has been created. Read only", "description": "Appliance UUID from which the node has been created. Read only",
"type": ["null", "string"], "type": "string",
"minLength": 36, "minLength": 36,
"maxLength": 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}$" "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}$"
}, },
"appliance_type": {
"description": "Type of node",
"enum": ["cloud", "ethernet_hub", "ethernet_switch", "docker", "dynamips", "vpcs", "traceng",
"virtualbox", "vmware", "iou", "qemu"]
},
"name": {
"description": "Appliance name",
"type": "string",
"minLength": 1,
},
"compute_id": { "compute_id": {
"description": "Compute identifier", "description": "Compute identifier",
"type": "string" "type": "string"
}, },
"default_name_format": {
"description": "Default name format",
"type": "string",
"minLength": 1
},
"symbol": {
"description": "Symbol of the appliance",
"type": "string",
"minLength": 1
},
"category": { "category": {
"description": "Appliance category", "description": "Appliance category",
"anyOf": [ "anyOf": [
@ -41,802 +56,18 @@ BASE_APPLIANCE_PROPERTIES = {
{"enum": ["router", "switch", "guest", "firewall"]} {"enum": ["router", "switch", "guest", "firewall"]}
] ]
}, },
"name": {
"description": "Appliance name",
"type": "string",
"minLength": 1,
},
"default_name_format": {
"description": "Default name format",
"type": "string",
"minLength": 1,
},
"symbol": {
"description": "Symbol of the appliance",
"type": "string",
"minLength": 1
},
"builtin": { "builtin": {
"description": "Appliance is builtin", "description": "Appliance is builtin",
"type": "boolean" "type": "boolean"
}, },
} }
#TODO: improve schema for Dynamips (match platform specific options, e.g. NPE allowd only for c7200)
DYNAMIPS_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["dynamips"]
},
"image": {
"description": "Path to the IOS image",
"type": "string",
"minLength": 1
},
"chassis": {
"description": "Chassis type",
"enum": ["1720","1721", "1750", "1751", "1760", "2610", "2620", "2610XM", "2620XM", "2650XM", "2621", "2611XM",
"2621XM", "2651XM", "3620", "3640", "3660", ""]
},
"platform": {
"description": "Platform type",
"enum": ["c1700", "c2600", "c2691", "c3725", "c3745", "c3600", "c7200"]
},
"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"
},
"exec_area": {
"description": "Exec area value",
"type": "integer",
},
"disk0": {
"description": "Disk0 size in MB",
"type": "integer"
},
"disk1": {
"description": "Disk1 size in MB",
"type": "integer"
},
"mac_addr": {
"description": "Base MAC address",
"type": "string",
"anyOf": [
{"pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$"},
{"pattern": "^$"}
]
},
"system_id": {
"description": "System ID",
"type": "string",
"minLength": 1,
},
"startup_config": {
"description": "IOS startup configuration file",
"type": "string"
},
"private_config": {
"description": "IOS private configuration file",
"type": "string"
},
"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",
},
"iomem": {
"description": "I/O memory percentage",
"type": "integer",
"minimum": 0,
"maximum": 100
},
"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"]
},
"auto_delete_disks": {
"description": "Automatically delete nvram and disk files",
"type": "boolean"
},
"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"]
},
"console_auto_start": {
"description": "Automatically start the console when the node has started",
"type": "boolean"
}
}
DYNAMIPS_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
IOU_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["iou"]
},
"path": {
"description": "Path of IOU executable",
"type": "string",
"minLength": 1
},
"ethernet_adapters": {
"description": "Number of ethernet adapters",
"type": "integer",
},
"serial_adapters": {
"description": "Number of serial adapters",
"type": "integer"
},
"ram": {
"description": "RAM in MB",
"type": "integer"
},
"nvram": {
"description": "NVRAM in KB",
"type": "integer"
},
"use_default_iou_values": {
"description": "Use default IOU values",
"type": "boolean"
},
"startup_config": {
"description": "Startup-config of IOU",
"type": "string"
},
"private_config": {
"description": "Private-config of IOU",
"type": "string"
},
"console_type": {
"description": "Console type",
"enum": ["telnet", "none"]
},
"console_auto_start": {
"description": "Automatically start the console when the node has started",
"type": "boolean"
},
}
IOU_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
DOCKER_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["docker"]
},
"image": {
"description": "Docker image name",
"type": "string",
"minLength": 1
},
"adapters": {
"description": "Number of adapters",
"type": "integer",
"minimum": 0,
"maximum": 99
},
"start_command": {
"description": "Docker CMD entry",
"type": "string",
"minLength": 1
},
"environment": {
"description": "Docker environment variables",
"type": "string",
"minLength": 1
},
"console_type": {
"description": "Console type",
"enum": ["telnet", "vnc", "http", "https", "none"]
},
"console_auto_start": {
"description": "Automatically start the console when the node has started",
"type": "boolean"
},
"console_http_port": {
"description": "Internal port in the container for the HTTP server",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"console_http_path": {
"description": "Path of the web interface",
"type": "string",
"minLength": 1
},
"console_resolution": {
"description": "Console resolution for VNC",
"type": "string",
"pattern": "^[0-9]+x[0-9]+$"
},
"extra_hosts": {
"description": "Docker extra hosts (added to /etc/hosts)",
"type": "string",
"minLength": 1
},
"custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA
}
DOCKER_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
QEMU_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["qemu"]
},
"usage": {
"description": "How to use the Qemu VM",
"type": "string",
"minLength": 1
},
"qemu_path": {
"description": "Path to QEMU",
"type": ["string", "null"],
"minLength": 1,
},
"platform": {
"description": "Platform to emulate",
"enum": QEMU_PLATFORMS
},
"linked_clone": {
"description": "Whether the VM is a linked clone or not",
"type": "boolean"
},
"ram": {
"description": "Amount of RAM in MB",
"type": "integer"
},
"cpus": {
"description": "Number of vCPUs",
"type": "integer",
"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})$"
},
"first_port_name": {
"description": "Optional name of the first networking port example: eth0",
"type": "string",
"minLength": 1
},
"port_name_format": {
"description": "Optional formatting of the networking port example: eth{0}",
"type": "string",
"minLength": 1
},
"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"
},
"console_type": {
"description": "Console type",
"enum": ["telnet", "vnc", "spice", "spice+agent", "none"]
},
"console_auto_start": {
"description": "Automatically start the console when the node has started",
"type": "boolean"
},
"boot_priority": {
"description": "QEMU boot priority",
"enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"]
},
"hda_disk_image": {
"description": "QEMU hda disk image path",
"type": "string",
"minLength": 1
},
"hda_disk_interface": {
"description": "QEMU hda interface",
"type": "string",
"minLength": 1
},
"hdb_disk_image": {
"description": "QEMU hdb disk image path",
"type": "string",
"minLength": 1
},
"hdb_disk_interface": {
"description": "QEMU hdb interface",
"type": "string",
"minLength": 1
},
"hdc_disk_image": {
"description": "QEMU hdc disk image path",
"type": "string",
"minLength": 1
},
"hdc_disk_interface": {
"description": "QEMU hdc interface",
"type": "string",
"minLength": 1
},
"hdd_disk_image": {
"description": "QEMU hdd disk image path",
"type": "string",
"minLength": 1
},
"hdd_disk_interface": {
"description": "QEMU hdd interface",
"type": "string",
"minLength": 1
},
"cdrom_image": {
"description": "QEMU cdrom image path",
"type": "string",
"minLength": 1
},
"initrd": {
"description": "QEMU initrd path",
"type": "string",
"minLength": 1
},
"kernel_image": {
"description": "QEMU kernel image path",
"type": "string",
"minLength": 1
},
"bios_image": {
"description": "QEMU bios image path",
"type": "string",
"minLength": 1
},
"kernel_command_line": {
"description": "QEMU kernel command line",
"type": "string",
"minLength": 1
},
"legacy_networking": {
"description": "Use QEMU legagy networking commands (-net syntax)",
"type": "boolean"
},
"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"
},
"process_priority": {
"description": "Process priority for QEMU",
"enum": ["realtime", "very high", "high", "normal", "low", "very low"]
},
"options": {
"description": "Additional QEMU options",
"type": "string",
"minLength": 1
},
"custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA
}
QEMU_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
VMWARE_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["vmware"]
},
"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"
},
"first_port_name": {
"description": "Optional name of the first networking port example: eth0",
"type": "string",
"minLength": 1
},
"port_name_format": {
"description": "Optional formatting of the networking port example: eth{0}",
"type": "string",
"minLength": 1
},
"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"
},
"adapters": {
"description": "Number of adapters",
"type": "integer",
"minimum": 0,
"maximum": 10, # maximum adapters support by VMware VMs
},
"adapter_type": {
"description": "VMware adapter type",
"type": "string",
"minLength": 1,
},
"use_any_adapter": {
"description": "Allow GNS3 to use any VMware adapter",
"type": "boolean",
},
"headless": {
"description": "Headless mode",
"type": "boolean"
},
"on_close": {
"description": "Action to execute on the VM is closed",
"enum": ["power_off", "shutdown_signal", "save_vm_state"],
},
"console_type": {
"description": "Console type",
"enum": ["telnet", "none"]
},
"console_auto_start": {
"description": "Automatically start the console when the node has started",
"type": "boolean"
},
"custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA
}
VMWARE_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
VIRTUALBOX_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["virtualbox"]
},
"vmname": {
"description": "VirtualBox VM name (in VirtualBox itself)",
"type": "string",
"minLength": 1,
},
"ram": {
"description": "Amount of RAM",
"minimum": 0,
"maximum": 65535,
"type": "integer"
},
"linked_clone": {
"description": "Whether the VM is a linked clone or not",
"type": "boolean"
},
"adapters": {
"description": "Number of adapters",
"type": "integer",
"minimum": 0,
"maximum": 36, # maximum given by the ICH9 chipset in VirtualBox
},
"use_any_adapter": {
"description": "Allow GNS3 to use any VirtualBox adapter",
"type": "boolean",
},
"adapter_type": {
"description": "VirtualBox adapter type",
"type": "string",
"minLength": 1,
},
"first_port_name": {
"description": "Optional name of the first networking port example: eth0",
"type": "string",
"minLength": 1
},
"port_name_format": {
"description": "Optional formatting of the networking port example: eth{0}",
"type": "string",
"minLength": 1
},
"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"
},
"headless": {
"description": "Headless mode",
"type": "boolean"
},
"on_close": {
"description": "Action to execute on the VM is closed",
"enum": ["power_off", "shutdown_signal", "save_vm_state"],
},
"console_type": {
"description": "Console type",
"enum": ["telnet", "none"]
},
"console_auto_start": {
"description": "Automatically start the console when the node has started",
"type": "boolean"
},
"custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA
}
VIRTUALBOX_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
TRACENG_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["traceng"]
},
"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"]
},
}
TRACENG_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
VPCS_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["vpcs"]
},
"base_script_file": {
"description": "Script file",
"type": "string",
"minLength": 1,
},
"console_type": {
"description": "Console type",
"enum": ["telnet", "none"]
},
"console_auto_start": {
"description": "Automatically start the console when the node has started",
"type": "boolean"
},
}
VPCS_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
ETHERNET_SWITCH_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["ethernet_switch"]
},
"ports_mapping": {
"type": "array",
"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"]
},
}
ETHERNET_SWITCH_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
ETHERNET_HUB_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["ethernet_hub"]
},
"ports_mapping": {
"type": "array",
"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_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
CLOUD_APPLIANCE_PROPERTIES = {
"appliance_type": {
"enum": ["cloud"]
},
"ports_mapping": {
"type": "array",
"items": [
PORT_OBJECT_SCHEMA
]
},
"remote_console_host": {
"description": "Remote console host or IP",
"type": ["string"],
"minLength": 1
},
"remote_console_port": {
"description": "Console TCP port",
"minimum": 1,
"maximum": 65535,
"type": "integer"
},
"remote_console_type": {
"description": "Console type",
"enum": ["telnet", "vnc", "spice", "http", "https", "none"]
},
"remote_console_http_path": {
"description": "Path of the remote web interface",
"type": "string",
"minLength": 1
},
}
CLOUD_APPLIANCE_PROPERTIES.update(BASE_APPLIANCE_PROPERTIES)
APPLIANCE_OBJECT_SCHEMA = { APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"description": "A template object", "description": "A template object",
"type": "object", "type": "object",
"definitions": { "properties": BASE_APPLIANCE_PROPERTIES,
"Dynamips": { "required": ["name", "appliance_type", "appliance_id", "category", "compute_id", "default_name_format", "symbol", "builtin"]
"description": "Dynamips appliance",
"properties": DYNAMIPS_APPLIANCE_PROPERTIES,
"additionalProperties": False,
"required": ["platform", "image", "ram"]
},
"IOU": {
"description": "IOU appliance",
"properties": IOU_APPLIANCE_PROPERTIES,
"additionalProperties": False,
"required": ["path"]
},
"Docker": {
"description": "Docker appliance",
"properties": DOCKER_APPLIANCE_PROPERTIES,
"additionalProperties": False,
"required": ["image"]
},
"Qemu": {
"description": "Qemu appliance",
"properties": QEMU_APPLIANCE_PROPERTIES,
"additionalProperties": False,
},
"VMware": {
"description": "VMware appliance",
"properties": VMWARE_APPLIANCE_PROPERTIES,
"additionalProperties": False,
"required": ["vmx_path", "linked_clone"]
},
"VirtualBox": {
"description": "VirtualBox appliance",
"properties": VIRTUALBOX_APPLIANCE_PROPERTIES,
"additionalProperties": False,
"required": ["vmname"]
},
"TraceNG": {
"description": "TraceNG appliance",
"properties": TRACENG_APPLIANCE_PROPERTIES,
"additionalProperties": False,
},
"VPCS": {
"description": "VPCS appliance",
"properties": VPCS_APPLIANCE_PROPERTIES,
"additionalProperties": False,
},
"EthernetSwitch": {
"description": "Ethernet switch appliance",
"properties": ETHERNET_SWITCH_APPLIANCE_PROPERTIES,
"additionalProperties": False,
},
"EthernetHub": {
"description": "Ethernet hub appliance",
"properties": ETHERNET_HUB_APPLIANCE_PROPERTIES,
"additionalProperties": False,
},
"Cloud": {
"description": "Cloud appliance",
"properties": CLOUD_APPLIANCE_PROPERTIES,
"additionalProperties": False,
},
},
"oneOf": [
{"$ref": "#/definitions/Dynamips"},
{"$ref": "#/definitions/IOU"},
{"$ref": "#/definitions/Docker"},
{"$ref": "#/definitions/Qemu"},
{"$ref": "#/definitions/VMware"},
{"$ref": "#/definitions/VirtualBox"},
{"$ref": "#/definitions/TraceNG"},
{"$ref": "#/definitions/VPCS"},
{"$ref": "#/definitions/EthernetSwitch"},
{"$ref": "#/definitions/EthernetHub"},
{"$ref": "#/definitions/Cloud"},
],
"required": ["name", "appliance_id", "appliance_type", "category", "compute_id", "default_name_format", "symbol"]
} }
APPLIANCE_CREATE_SCHEMA = copy.deepcopy(APPLIANCE_OBJECT_SCHEMA) APPLIANCE_CREATE_SCHEMA = copy.deepcopy(APPLIANCE_OBJECT_SCHEMA)
@ -844,9 +75,10 @@ APPLIANCE_CREATE_SCHEMA = copy.deepcopy(APPLIANCE_OBJECT_SCHEMA)
# create schema # create schema
# these properties are not required to create an appliance # these properties are not required to create an appliance
APPLIANCE_CREATE_SCHEMA["required"].remove("appliance_id") APPLIANCE_CREATE_SCHEMA["required"].remove("appliance_id")
APPLIANCE_CREATE_SCHEMA["required"].remove("compute_id") APPLIANCE_CREATE_SCHEMA["required"].remove("category")
APPLIANCE_CREATE_SCHEMA["required"].remove("default_name_format") APPLIANCE_CREATE_SCHEMA["required"].remove("default_name_format")
APPLIANCE_CREATE_SCHEMA["required"].remove("symbol") APPLIANCE_CREATE_SCHEMA["required"].remove("symbol")
APPLIANCE_CREATE_SCHEMA["required"].remove("builtin")
# update schema # update schema
APPLIANCE_UPDATE_SCHEMA = copy.deepcopy(APPLIANCE_OBJECT_SCHEMA) APPLIANCE_UPDATE_SCHEMA = copy.deepcopy(APPLIANCE_OBJECT_SCHEMA)

View File

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
from .port import PORT_OBJECT_SCHEMA
CLOUD_APPLIANCE_PROPERTIES = {
"ports_mapping": {
"type": "array",
"items": [PORT_OBJECT_SCHEMA]
},
"remote_console_host": {
"description": "Remote console host or IP",
"type": ["string"],
"minLength": 1
},
"remote_console_port": {
"description": "Console TCP port",
"minimum": 1,
"maximum": 65535,
"type": "integer"
},
"remote_console_type": {
"description": "Console type",
"enum": ["telnet", "vnc", "spice", "http", "https", "none"]
},
"remote_console_http_path": {
"description": "Path of the remote web interface",
"type": "string",
"minLength": 1
},
}
CLOUD_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
CLOUD_APPLIANCE_PROPERTIES["category"]["default"] = "guest"
CLOUD_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "Cloud{0}"
CLOUD_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/cloud.svg"
CLOUD_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A cloud template object",
"type": "object",
"properties": CLOUD_APPLIANCE_PROPERTIES,
"additionalProperties": False
}

View File

@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA
DOCKER_APPLIANCE_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"
},
"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": "",
},
"custom_adapters": CUSTOM_ADAPTERS_ARRAY_SCHEMA
}
DOCKER_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
DOCKER_APPLIANCE_PROPERTIES["category"]["default"] = "guest"
DOCKER_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "{name}-{0}"
DOCKER_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/docker_guest.svg"
DOCKER_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A Docker template object",
"type": "object",
"properties": DOCKER_APPLIANCE_PROPERTIES,
"required": ["image"],
"additionalProperties": False
}

View File

@ -0,0 +1,399 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
from .dynamips_vm import DYNAMIPS_ADAPTERS, DYNAMIPS_WICS
DYNAMIPS_APPLIANCE_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
}
}
DYNAMIPS_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
DYNAMIPS_APPLIANCE_PROPERTIES["category"]["default"] = "router"
DYNAMIPS_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "R{0}"
DYNAMIPS_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/router.svg"
DYNAMIPS_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A Dynamips template object",
"type": "object",
"properties": DYNAMIPS_APPLIANCE_PROPERTIES,
"required": ["platform", "image"],
}
C7200_DYNAMIPS_APPLIANCE_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_APPLIANCE_PROPERTIES.update(DYNAMIPS_APPLIANCE_PROPERTIES)
C7200_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A c7200 Dynamips template object",
"type": "object",
"properties": C7200_DYNAMIPS_APPLIANCE_PROPERTIES,
"additionalProperties": False
}
C3745_DYNAMIPS_APPLIANCE_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_APPLIANCE_PROPERTIES.update(DYNAMIPS_APPLIANCE_PROPERTIES)
C3745_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A c3745 Dynamips template object",
"type": "object",
"properties": C3745_DYNAMIPS_APPLIANCE_PROPERTIES,
"additionalProperties": False
}
C3725_DYNAMIPS_APPLIANCE_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_APPLIANCE_PROPERTIES.update(DYNAMIPS_APPLIANCE_PROPERTIES)
C3725_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A c3725 Dynamips template object",
"type": "object",
"properties": C3725_DYNAMIPS_APPLIANCE_PROPERTIES,
"additionalProperties": False
}
C3600_DYNAMIPS_APPLIANCE_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_APPLIANCE_PROPERTIES.update(DYNAMIPS_APPLIANCE_PROPERTIES)
C3600_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A c3600 Dynamips template object",
"type": "object",
"properties": C3600_DYNAMIPS_APPLIANCE_PROPERTIES,
"required": ["chassis"],
"additionalProperties": False
}
C2691_DYNAMIPS_APPLIANCE_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_APPLIANCE_PROPERTIES.update(DYNAMIPS_APPLIANCE_PROPERTIES)
C2691_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A c2691 Dynamips template object",
"type": "object",
"properties": C2691_DYNAMIPS_APPLIANCE_PROPERTIES,
"additionalProperties": False
}
C2600_DYNAMIPS_APPLIANCE_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_APPLIANCE_PROPERTIES.update(DYNAMIPS_APPLIANCE_PROPERTIES)
C2600_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A c2600 Dynamips template object",
"type": "object",
"properties": C2600_DYNAMIPS_APPLIANCE_PROPERTIES,
"required": ["chassis"],
"additionalProperties": False
}
C1700_DYNAMIPS_APPLIANCE_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_APPLIANCE_PROPERTIES.update(DYNAMIPS_APPLIANCE_PROPERTIES)
C1700_DYNAMIPS_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A c1700 Dynamips template object",
"type": "object",
"properties": C1700_DYNAMIPS_APPLIANCE_PROPERTIES,
"required": ["chassis"],
"additionalProperties": False
}

View File

@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
ETHERNET_HUB_APPLIANCE_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_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
ETHERNET_HUB_APPLIANCE_PROPERTIES["category"]["default"] = "switch"
ETHERNET_HUB_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "Hub{0}"
ETHERNET_HUB_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/hub.svg"
ETHERNET_HUB_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "An Ethernet hub template object",
"type": "object",
"properties": ETHERNET_HUB_APPLIANCE_PROPERTIES,
"additionalProperties": False
}

View File

@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
ETHERNET_SWITCH_APPLIANCE_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": "telnet"
},
}
ETHERNET_SWITCH_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
ETHERNET_SWITCH_APPLIANCE_PROPERTIES["category"]["default"] = "switch"
ETHERNET_SWITCH_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "Switch{0}"
ETHERNET_SWITCH_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/ethernet_switch.svg"
ETHERNET_SWITCH_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "An Ethernet switch template object",
"type": "object",
"properties": ETHERNET_SWITCH_APPLIANCE_PROPERTIES,
"additionalProperties": False
}

View File

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
IOU_APPLIANCE_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": ""
},
"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_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
IOU_APPLIANCE_PROPERTIES["category"]["default"] = "router"
IOU_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "IOU{0}"
IOU_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/multilayer_switch.svg"
IOU_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A IOU template object",
"type": "object",
"properties": IOU_APPLIANCE_PROPERTIES,
"required": ["path"],
"additionalProperties": False
}

View File

@ -0,0 +1,217 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA
from .qemu import QEMU_PLATFORMS
QEMU_APPLIANCE_PROPERTIES = {
"usage": {
"description": "How to use the Qemu VM",
"type": "string",
"default": ""
},
"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
},
"adapters": {
"description": "Number of adapters",
"type": "integer",
"minimum": 0,
"maximum": 275,
"default": 1
},
"adapter_type": {
"description": "QEMU adapter type",
"type": "string",
"enum": ["e1000", "i82550", "i82551", "i82557a", "i82557b", "i82557c", "i82558a","i82558b", "i82559a",
"i82559b", "i82559c", "i82559er", "i82562", "i82801", "ne2k_pci", "pcnet", "rtl8139", "virtio",
"virtio-net-pci", "vmxnet3"],
"default": "e1000"
},
"mac_address": {
"description": "QEMU MAC address",
"type": "string",
"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
},
"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", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"],
"default": "ide"
},
"hdb_disk_image": {
"description": "QEMU hdb disk image path",
"type": "string",
"default": ""
},
"hdb_disk_interface": {
"description": "QEMU hdb interface",
"enum": ["ide", "sata", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"],
"default": "ide"
},
"hdc_disk_image": {
"description": "QEMU hdc disk image path",
"type": "string",
"default": ""
},
"hdc_disk_interface": {
"description": "QEMU hdc interface",
"enum": ["ide", "sata", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"],
"default": "ide"
},
"hdd_disk_image": {
"description": "QEMU hdd disk image path",
"type": "string",
"default": ""
},
"hdd_disk_interface": {
"description": "QEMU hdd interface",
"enum": ["ide", "sata", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"],
"default": "ide"
},
"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
},
"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_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
QEMU_APPLIANCE_PROPERTIES["category"]["default"] = "guest"
QEMU_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "{name}-{0}"
QEMU_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/qemu_guest.svg"
QEMU_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A Qemu template object",
"type": "object",
"properties": QEMU_APPLIANCE_PROPERTIES,
"additionalProperties": False
}

View File

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
TRACENG_APPLIANCE_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_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
TRACENG_APPLIANCE_PROPERTIES["category"]["default"] = "guest"
TRACENG_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "TraceNG{0}"
TRACENG_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/traceng.svg"
TRACENG_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A TraceNG template object",
"type": "object",
"properties": TRACENG_APPLIANCE_PROPERTIES,
"additionalProperties": False
}

View File

@ -0,0 +1,113 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA
VIRTUALBOX_APPLIANCE_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_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
VIRTUALBOX_APPLIANCE_PROPERTIES["category"]["default"] = "guest"
VIRTUALBOX_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "{name}-{0}"
VIRTUALBOX_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/vbox_guest.svg"
VIRTUALBOX_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A VirtualBox template object",
"type": "object",
"properties": VIRTUALBOX_APPLIANCE_PROPERTIES,
"required": ["vmname"],
"additionalProperties": False
}

View File

@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
from .custom_adapters import CUSTOM_ADAPTERS_ARRAY_SCHEMA
VMWARE_APPLIANCE_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_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
VMWARE_APPLIANCE_PROPERTIES["category"]["default"] = "guest"
VMWARE_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "{name}-{0}"
VMWARE_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/vmware_guest.svg"
VMWARE_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A VMware template object",
"type": "object",
"properties": VMWARE_APPLIANCE_PROPERTIES,
"required": ["vmx_path"],
"additionalProperties": False
}

View File

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from .appliance import BASE_APPLIANCE_PROPERTIES
VPCS_APPLIANCE_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_APPLIANCE_PROPERTIES.update(copy.deepcopy(BASE_APPLIANCE_PROPERTIES))
VPCS_APPLIANCE_PROPERTIES["category"]["default"] = "guest"
VPCS_APPLIANCE_PROPERTIES["default_name_format"]["default"] = "PC{0}"
VPCS_APPLIANCE_PROPERTIES["symbol"]["default"] = ":/symbols/vpcs_guest.svg"
VPCS_APPLIANCE_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "A VPCS template object",
"type": "object",
"properties": VPCS_APPLIANCE_PROPERTIES,
"additionalProperties": False
}

View File

@ -23,7 +23,7 @@ import aiohttp
import logging import logging
import traceback import traceback
import jsonschema import jsonschema
import jsonschema.exceptions
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -58,10 +58,12 @@ async def parse_request(request, input_schema, raw):
try: try:
jsonschema.validate(request.json, input_schema) jsonschema.validate(request.json, input_schema)
except jsonschema.ValidationError as e: except jsonschema.ValidationError as e:
log.error("Invalid input query. JSON schema error: {}".format(e.message)) message = "JSON schema error with API request '{}' and JSON data '{}': {}".format(request.path_qs,
raise aiohttp.web.HTTPBadRequest(text="Invalid JSON: {} in schema: {}".format( request.json,
e.message, e.message)
json.dumps(e.schema))) log.error(message)
log.debug("Input schema: {}".format(json.dumps(input_schema)))
raise aiohttp.web.HTTPBadRequest(text=message)
return request return request

View File

@ -15,6 +15,9 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import jsonschema
from gns3server.controller.appliance import Appliance from gns3server.controller.appliance import Appliance
@ -26,42 +29,25 @@ def test_appliance_json():
"category": 0, "category": 0,
"symbol": "qemu.svg", "symbol": "qemu.svg",
"server": "local", "server": "local",
"platform": None "platform": "i386"
}) })
assert a.__json__() == { settings = a.__json__()
"appliance_id": a.id, assert settings["appliance_id"] == a.id
"appliance_type": "qemu", assert settings["appliance_type"] == "qemu"
"builtin": False, assert settings["builtin"] == False
"name": "Test",
"default_name_format": "{name}-{0}",
"category": "router",
"symbol": "qemu.svg",
"compute_id": "local",
"platform": None
}
def test_appliance_json_with_not_known_category(): def test_appliance_json_with_not_known_category():
a = Appliance(None, { with pytest.raises(jsonschema.ValidationError):
"node_type": "qemu", a = Appliance(None, {
"name": "Test", "node_type": "qemu",
"default_name_format": "{name}-{0}", "name": "Test",
"category": 'Not known', "default_name_format": "{name}-{0}",
"symbol": "qemu.svg", "category": 'Not known',
"server": "local", "symbol": "qemu.svg",
"platform": None "server": "local",
}) "platform": "i386"
assert a.__json__() == { })
"appliance_id": a.id,
"appliance_type": "qemu",
"builtin": False,
"name": "Test",
"default_name_format": "{name}-{0}",
"category": "Not known",
"symbol": "qemu.svg",
"compute_id": "local",
"platform": None
}
def test_appliance_json_with_platform(): def test_appliance_json_with_platform():
@ -71,20 +57,15 @@ def test_appliance_json_with_platform():
"default_name_format": "{name}-{0}", "default_name_format": "{name}-{0}",
"category": 0, "category": 0,
"symbol": "dynamips.svg", "symbol": "dynamips.svg",
"image": "IOS_image.bin",
"server": "local", "server": "local",
"platform": "c3725" "platform": "c3725"
}) })
assert a.__json__() == { settings = a.__json__()
"appliance_id": a.id, assert settings["appliance_id"] == a.id
"appliance_type": "dynamips", assert settings["appliance_type"] == "dynamips"
"builtin": False, assert settings["builtin"] == False
"name": "Test", assert settings["platform"] == "c3725"
"default_name_format": "{name}-{0}",
"category": "router",
"symbol": "dynamips.svg",
"compute_id": "local",
"platform": "c3725"
}
def test_appliance_fix_linked_base(): def test_appliance_fix_linked_base():

View File

@ -213,14 +213,10 @@ def test_add_node_from_appliance(async_run, controller):
project = Project(controller=controller, name="Test") project = Project(controller=controller, name="Test")
controller._notification = MagicMock() controller._notification = MagicMock()
appliance = Appliance(str(uuid.uuid4()), { appliance = Appliance(str(uuid.uuid4()), {
"server": "local", "compute_id": "local",
"name": "Test", "name": "Test",
"default_name_format": "{name}-{0}",
"appliance_type": "vpcs", "appliance_type": "vpcs",
"builtin": False, "builtin": False,
"properties": {
"a": 1
}
}) })
controller._appliances[appliance.id] = appliance controller._appliances[appliance.id] = appliance
controller._computes["local"] = compute controller._computes["local"] = compute
@ -230,30 +226,15 @@ def test_add_node_from_appliance(async_run, controller):
compute.post = AsyncioMagicMock(return_value=response) compute.post = AsyncioMagicMock(return_value=response)
node = async_run(project.add_node_from_appliance(appliance.id, x=23, y=12)) node = async_run(project.add_node_from_appliance(appliance.id, x=23, y=12))
compute.post.assert_any_call('/projects', data={ compute.post.assert_any_call('/projects', data={
"name": project._name, "name": project._name,
"project_id": project._id, "project_id": project._id,
"path": project._path "path": project._path
}) })
compute.post.assert_any_call('/projects/{}/vpcs/nodes'.format(project.id),
data={'node_id': node.id,
'name': 'Test-1',
'a': 1,
},
timeout=1200)
assert compute in project._project_created_on_compute assert compute in project._project_created_on_compute
controller.notification.project_emit.assert_any_call("node.created", node.__json__()) controller.notification.project_emit.assert_any_call("node.created", node.__json__())
# Make sure we can call twice the node creation
node = async_run(project.add_node_from_appliance(appliance.id, x=13, y=12))
compute.post.assert_any_call('/projects/{}/vpcs/nodes'.format(project.id),
data={'node_id': node.id,
'name': 'Test-2',
'a': 1
},
timeout=1200)
def test_delete_node(async_run, controller): def test_delete_node(async_run, controller):
""" """

View File

@ -113,6 +113,24 @@ def test_appliance_create_with_id(http_controller, controller):
assert len(controller.appliances) == 1 assert len(controller.appliances) == 1
def test_appliance_create_wrong_type(http_controller, controller):
params = {"appliance_id": str(uuid.uuid4()),
"base_script_file": "vpcs_base_config.txt",
"category": "guest",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "PC{0}",
"name": "VPCS_TEST",
"compute_id": "local",
"symbol": ":/symbols/vpcs_guest.svg",
"appliance_type": "invalid_appliance_type"}
response = http_controller.post("/appliances", params)
assert response.status == 400
assert len(controller.appliances) == 0
def test_appliance_get(http_controller, controller): def test_appliance_get(http_controller, controller):
appliance_id = str(uuid.uuid4()) appliance_id = str(uuid.uuid4())
@ -192,6 +210,729 @@ def test_appliance_delete(http_controller, controller):
assert len(controller.appliances) == 0 assert len(controller.appliances) == 0
def test_c7200_dynamips_appliance_create(http_controller):
params = {"name": "Cisco c7200 appliance",
"platform": "c7200",
"compute_id": "local",
"image": "c7200-adventerprisek9-mz.124-24.T5.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "dynamips",
"auto_delete_disks": False,
"builtin": False,
"category": "router",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "R{0}",
"disk0": 0,
"disk1": 0,
"exec_area": 64,
"idlemax": 500,
"idlepc": "",
"idlesleep": 30,
"image": "c7200-adventerprisek9-mz.124-24.T5.image",
"mac_addr": "",
"midplane": "vxr",
"mmap": True,
"name": "Cisco c7200 appliance",
"npe": "npe-400",
"nvram": 512,
"platform": "c7200",
"private_config": "",
"ram": 512,
"sparsemem": True,
"startup_config": "ios_base_startup-config.txt",
"symbol": ":/symbols/router.svg",
"system_id": "FTX0945W0MY"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_c3745_dynamips_appliance_create(http_controller):
params = {"name": "Cisco c3745 appliance",
"platform": "c3745",
"compute_id": "local",
"image": "c3745-adventerprisek9-mz.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "dynamips",
"auto_delete_disks": False,
"builtin": False,
"category": "router",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "R{0}",
"disk0": 0,
"disk1": 0,
"exec_area": 64,
"idlemax": 500,
"idlepc": "",
"idlesleep": 30,
"image": "c3745-adventerprisek9-mz.124-25d.image",
"mac_addr": "",
"mmap": True,
"name": "Cisco c3745 appliance",
"iomem": 5,
"nvram": 256,
"platform": "c3745",
"private_config": "",
"ram": 256,
"sparsemem": True,
"startup_config": "ios_base_startup-config.txt",
"symbol": ":/symbols/router.svg",
"system_id": "FTX0945W0MY"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_c3725_dynamips_appliance_create(http_controller):
params = {"name": "Cisco c3725 appliance",
"platform": "c3725",
"compute_id": "local",
"image": "c3725-adventerprisek9-mz.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "dynamips",
"auto_delete_disks": False,
"builtin": False,
"category": "router",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "R{0}",
"disk0": 0,
"disk1": 0,
"exec_area": 64,
"idlemax": 500,
"idlepc": "",
"idlesleep": 30,
"image": "c3725-adventerprisek9-mz.124-25d.image",
"mac_addr": "",
"mmap": True,
"name": "Cisco c3725 appliance",
"iomem": 5,
"nvram": 256,
"platform": "c3725",
"private_config": "",
"ram": 128,
"sparsemem": True,
"startup_config": "ios_base_startup-config.txt",
"symbol": ":/symbols/router.svg",
"system_id": "FTX0945W0MY"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_c3600_dynamips_appliance_create(http_controller):
params = {"name": "Cisco c3600 appliance",
"platform": "c3600",
"chassis": "3660",
"compute_id": "local",
"image": "c3660-a3jk9s-mz.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "dynamips",
"auto_delete_disks": False,
"builtin": False,
"category": "router",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "R{0}",
"disk0": 0,
"disk1": 0,
"exec_area": 64,
"idlemax": 500,
"idlepc": "",
"idlesleep": 30,
"image": "c3660-a3jk9s-mz.124-25d.image",
"mac_addr": "",
"mmap": True,
"name": "Cisco c3600 appliance",
"iomem": 5,
"nvram": 128,
"platform": "c3600",
"chassis": "3660",
"private_config": "",
"ram": 192,
"sparsemem": True,
"startup_config": "ios_base_startup-config.txt",
"symbol": ":/symbols/router.svg",
"system_id": "FTX0945W0MY"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_c3600_dynamips_appliance_create_wrong_chassis(http_controller):
params = {"name": "Cisco c3600 appliance",
"platform": "c3600",
"chassis": "3650",
"compute_id": "local",
"image": "c3660-a3jk9s-mz.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params)
assert response.status == 400
def test_c2691_dynamips_appliance_create(http_controller):
params = {"name": "Cisco c2691 appliance",
"platform": "c2691",
"compute_id": "local",
"image": "c2691-adventerprisek9-mz.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "dynamips",
"auto_delete_disks": False,
"builtin": False,
"category": "router",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "R{0}",
"disk0": 0,
"disk1": 0,
"exec_area": 64,
"idlemax": 500,
"idlepc": "",
"idlesleep": 30,
"image": "c2691-adventerprisek9-mz.124-25d.image",
"mac_addr": "",
"mmap": True,
"name": "Cisco c2691 appliance",
"iomem": 5,
"nvram": 256,
"platform": "c2691",
"private_config": "",
"ram": 192,
"sparsemem": True,
"startup_config": "ios_base_startup-config.txt",
"symbol": ":/symbols/router.svg",
"system_id": "FTX0945W0MY"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_c2600_dynamips_appliance_create(http_controller):
params = {"name": "Cisco c2600 appliance",
"platform": "c2600",
"chassis": "2651XM",
"compute_id": "local",
"image": "c2600-adventerprisek9-mz.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "dynamips",
"auto_delete_disks": False,
"builtin": False,
"category": "router",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "R{0}",
"disk0": 0,
"disk1": 0,
"exec_area": 64,
"idlemax": 500,
"idlepc": "",
"idlesleep": 30,
"image": "c2600-adventerprisek9-mz.124-25d.image",
"mac_addr": "",
"mmap": True,
"name": "Cisco c2600 appliance",
"iomem": 15,
"nvram": 128,
"platform": "c2600",
"chassis": "2651XM",
"private_config": "",
"ram": 160,
"sparsemem": True,
"startup_config": "ios_base_startup-config.txt",
"symbol": ":/symbols/router.svg",
"system_id": "FTX0945W0MY"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_c2600_dynamips_appliance_create_wrong_chassis(http_controller):
params = {"name": "Cisco c2600 appliance",
"platform": "c2600",
"chassis": "2660XM",
"compute_id": "local",
"image": "c2600-adventerprisek9-mz.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params)
assert response.status == 400
def test_c1700_dynamips_appliance_create(http_controller):
params = {"name": "Cisco c1700 appliance",
"platform": "c1700",
"chassis": "1760",
"compute_id": "local",
"image": "c1700-adventerprisek9-mz.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "dynamips",
"auto_delete_disks": False,
"builtin": False,
"category": "router",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "R{0}",
"disk0": 0,
"disk1": 0,
"exec_area": 64,
"idlemax": 500,
"idlepc": "",
"idlesleep": 30,
"image": "c1700-adventerprisek9-mz.124-25d.image",
"mac_addr": "",
"mmap": True,
"name": "Cisco c1700 appliance",
"iomem": 15,
"nvram": 128,
"platform": "c1700",
"chassis": "1760",
"private_config": "",
"ram": 160,
"sparsemem": False,
"startup_config": "ios_base_startup-config.txt",
"symbol": ":/symbols/router.svg",
"system_id": "FTX0945W0MY"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_c1700_dynamips_appliance_create_wrong_chassis(http_controller):
params = {"name": "Cisco c1700 appliance",
"platform": "c1700",
"chassis": "1770",
"compute_id": "local",
"image": "c1700-adventerprisek9-mz.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params)
assert response.status == 400
def test_dynamips_appliance_create_wrong_platform(http_controller):
params = {"name": "Cisco c3900 appliance",
"platform": "c3900",
"compute_id": "local",
"image": "c3900-test.124-25d.image",
"appliance_type": "dynamips"}
response = http_controller.post("/appliances", params)
assert response.status == 400
def test_iou_appliance_create(http_controller):
params = {"name": "IOU appliance",
"compute_id": "local",
"path": "/path/to/i86bi_linux-ipbase-ms-12.4.bin",
"appliance_type": "iou"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "iou",
"builtin": False,
"category": "router",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "IOU{0}",
"ethernet_adapters": 2,
"name": "IOU appliance",
"nvram": 128,
"path": "/path/to/i86bi_linux-ipbase-ms-12.4.bin",
"private_config": "",
"ram": 256,
"serial_adapters": 2,
"startup_config": "iou_l3_base_startup-config.txt",
"symbol": ":/symbols/multilayer_switch.svg",
"use_default_iou_values": True}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_docker_appliance_create(http_controller):
params = {"name": "Docker appliance",
"compute_id": "local",
"image": "gns3/endhost:latest",
"appliance_type": "docker"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"adapters": 1,
"appliance_type": "docker",
"builtin": False,
"category": "guest",
"compute_id": "local",
"console_auto_start": False,
"console_http_path": "/",
"console_http_port": 80,
"console_resolution": "1024x768",
"console_type": "telnet",
"default_name_format": "{name}-{0}",
"environment": "",
"extra_hosts": "",
"image": "gns3/endhost:latest",
"name": "Docker appliance",
"start_command": "",
"symbol": ":/symbols/docker_guest.svg"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_qemu_appliance_create(http_controller):
params = {"name": "Qemu appliance",
"compute_id": "local",
"platform": "i386",
"hda_disk_image": "IOSvL2-15.2.4.0.55E.qcow2",
"ram": 512,
"appliance_type": "qemu"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"adapter_type": "e1000",
"adapters": 1,
"appliance_type": "qemu",
"bios_image": "",
"boot_priority": "c",
"builtin": False,
"category": "guest",
"cdrom_image": "",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"cpu_throttling": 0,
"cpus": 1,
"default_name_format": "{name}-{0}",
"first_port_name": "",
"hda_disk_image": "IOSvL2-15.2.4.0.55E.qcow2",
"hda_disk_interface": "ide",
"hdb_disk_image": "",
"hdb_disk_interface": "ide",
"hdc_disk_image": "",
"hdc_disk_interface": "ide",
"hdd_disk_image": "",
"hdd_disk_interface": "ide",
"initrd": "",
"kernel_command_line": "",
"kernel_image": "",
"legacy_networking": False,
"linked_clone": True,
"mac_address": "",
"name": "Qemu appliance",
"on_close": "power_off",
"options": "",
"platform": "i386",
"port_name_format": "Ethernet{0}",
"port_segment_size": 0,
"process_priority": "normal",
"qemu_path": "",
"ram": 512,
"symbol": ":/symbols/qemu_guest.svg",
"usage": ""}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_vmware_appliance_create(http_controller):
params = {"name": "VMware appliance",
"compute_id": "local",
"appliance_type": "vmware",
"vmx_path": "/path/to/vm.vmx"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"adapter_type": "e1000",
"adapters": 1,
"appliance_type": "vmware",
"builtin": False,
"category": "guest",
"compute_id": "local",
"console_auto_start": False,
"console_type": "none",
"default_name_format": "{name}-{0}",
"first_port_name": "",
"headless": False,
"linked_clone": False,
"name": "VMware appliance",
"on_close": "power_off",
"port_name_format": "Ethernet{0}",
"port_segment_size": 0,
"symbol": ":/symbols/vmware_guest.svg",
"use_any_adapter": False,
"vmx_path": "/path/to/vm.vmx"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_virtualbox_appliance_create(http_controller):
params = {"name": "VirtualBox appliance",
"compute_id": "local",
"appliance_type": "virtualbox",
"vmname": "My VirtualBox VM"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"adapter_type": "Intel PRO/1000 MT Desktop (82540EM)",
"adapters": 1,
"appliance_type": "virtualbox",
"builtin": False,
"category": "guest",
"compute_id": "local",
"console_auto_start": False,
"console_type": "none",
"default_name_format": "{name}-{0}",
"first_port_name": "",
"headless": False,
"linked_clone": False,
"name": "VirtualBox appliance",
"on_close": "power_off",
"port_name_format": "Ethernet{0}",
"port_segment_size": 0,
"ram": 256,
"symbol": ":/symbols/vbox_guest.svg",
"use_any_adapter": False,
"vmname": "My VirtualBox VM"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_vpcs_appliance_create(http_controller):
params = {"name": "VPCS appliance",
"compute_id": "local",
"appliance_type": "vpcs"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "vpcs",
"base_script_file": "vpcs_base_config.txt",
"builtin": False,
"category": "guest",
"compute_id": "local",
"console_auto_start": False,
"console_type": "telnet",
"default_name_format": "PC{0}",
"name": "VPCS appliance",
"symbol": ":/symbols/vpcs_guest.svg"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_ethernet_switch_appliance_create(http_controller):
params = {"name": "Ethernet switch appliance",
"compute_id": "local",
"appliance_type": "ethernet_switch"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "ethernet_switch",
"builtin": False,
"category": "switch",
"compute_id": "local",
"console_type": "telnet",
"default_name_format": "Switch{0}",
"name": "Ethernet switch appliance",
"ports_mapping": [{"ethertype": "",
"name": "Ethernet0",
"port_number": 0,
"type": "access",
"vlan": 1
},
{"ethertype": "",
"name": "Ethernet1",
"port_number": 1,
"type": "access",
"vlan": 1
},
{"ethertype": "",
"name": "Ethernet2",
"port_number": 2,
"type": "access",
"vlan": 1
},
{"ethertype": "",
"name": "Ethernet3",
"port_number": 3,
"type": "access",
"vlan": 1
},
{"ethertype": "",
"name": "Ethernet4",
"port_number": 4,
"type": "access",
"vlan": 1
},
{"ethertype": "",
"name": "Ethernet5",
"port_number": 5,
"type": "access",
"vlan": 1
},
{"ethertype": "",
"name": "Ethernet6",
"port_number": 6,
"type": "access",
"vlan": 1
},
{"ethertype": "",
"name": "Ethernet7",
"port_number": 7,
"type": "access",
"vlan": 1
}],
"symbol": ":/symbols/ethernet_switch.svg"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_cloud_appliance_create(http_controller):
params = {"name": "Cloud appliance",
"compute_id": "local",
"appliance_type": "cloud"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"appliance_type": "cloud",
"builtin": False,
"category": "guest",
"compute_id": "local",
"default_name_format": "Cloud{0}",
"name": "Cloud appliance",
"symbol": ":/symbols/cloud.svg"}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_ethernet_hub_appliance_create(http_controller):
params = {"name": "Ethernet hub appliance",
"compute_id": "local",
"appliance_type": "ethernet_hub"}
response = http_controller.post("/appliances", params, example=True)
assert response.status == 201
assert response.json["appliance_id"] is not None
expected_response = {"ports_mapping": [{"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"
}],
"compute_id": "local",
"name": "Ethernet hub appliance",
"symbol": ":/symbols/hub.svg",
"default_name_format": "Hub{0}",
"appliance_type": "ethernet_hub",
"category": "switch",
"builtin": False}
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_create_node_from_appliance(http_controller, controller, project, compute): def test_create_node_from_appliance(http_controller, controller, project, compute):
id = str(uuid.uuid4()) id = str(uuid.uuid4())
@ -209,6 +950,5 @@ def test_create_node_from_appliance(http_controller, controller, project, comput
"y": 12 "y": 12
}) })
mock.assert_called_with(id, x=42, y=12, compute_id=None) mock.assert_called_with(id, x=42, y=12, compute_id=None)
print(response.body)
assert response.route == "/projects/{project_id}/appliances/{appliance_id}" assert response.route == "/projects/{project_id}/appliances/{appliance_id}"
assert response.status == 201 assert response.status == 201