mirror of
https://github.com/GNS3/gns3-server
synced 2024-12-29 02:08:10 +00:00
Working dedicated appliance management API. Ref https://github.com/GNS3/gns3-server/issues/1427
This commit is contained in:
parent
f0fe9d39fa
commit
089fdff4f1
@ -174,9 +174,12 @@ class Controller:
|
||||
"""
|
||||
|
||||
appliance = self._appliances.get(appliance_id)
|
||||
if not appliance:
|
||||
raise aiohttp.web.HTTPNotFound(text="Appliance ID {} doesn't exist".format(appliance_id))
|
||||
if appliance.builtin:
|
||||
raise aiohttp.web.HTTPConflict(text="Appliance ID {} cannot be deleted because it is builtin".format(appliance_id))
|
||||
raise aiohttp.web.HTTPConflict(text="Appliance ID {} cannot be deleted because it is a builtin".format(appliance_id))
|
||||
self._appliances.pop(appliance_id)
|
||||
self.save()
|
||||
|
||||
def load_appliances(self):
|
||||
|
||||
@ -184,17 +187,17 @@ class Controller:
|
||||
|
||||
# Add builtins
|
||||
builtins = []
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "cloud"), {"node_type": "cloud", "name": "Cloud", "category": 2, "symbol": ":/symbols/cloud.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "nat"), {"node_type": "nat", "name": "NAT", "category": 2, "symbol": ":/symbols/cloud.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "vpcs"), {"node_type": "vpcs", "name": "VPCS", "default_name_format": "PC-{0}", "category": 2, "symbol": ":/symbols/vpcs_guest.svg", "properties": {"base_script_file": "vpcs_base_config.txt"}}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "ethernet_switch"), {"node_type": "ethernet_switch", "console_type": "telnet", "name": "Ethernet switch", "category": 1, "symbol": ":/symbols/ethernet_switch.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "ethernet_hub"), {"node_type": "ethernet_hub", "name": "Ethernet hub", "category": 1, "symbol": ":/symbols/hub.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "frame_relay_switch"), {"node_type": "frame_relay_switch", "name": "Frame Relay switch", "category": 1, "symbol": ":/symbols/frame_relay_switch.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "atm_switch"), {"node_type": "atm_switch", "name": "ATM switch", "category": 1, "symbol": ":/symbols/atm_switch.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "cloud"), {"appliance_type": "cloud", "name": "Cloud", "category": 2, "symbol": ":/symbols/cloud.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "nat"), {"appliance_type": "nat", "name": "NAT", "category": 2, "symbol": ":/symbols/cloud.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "vpcs"), {"appliance_type": "vpcs", "name": "VPCS", "default_name_format": "PC-{0}", "category": 2, "symbol": ":/symbols/vpcs_guest.svg", "properties": {"base_script_file": "vpcs_base_config.txt"}}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "ethernet_switch"), {"appliance_type": "ethernet_switch", "console_type": "telnet", "name": "Ethernet switch", "category": 1, "symbol": ":/symbols/ethernet_switch.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "ethernet_hub"), {"appliance_type": "ethernet_hub", "name": "Ethernet hub", "category": 1, "symbol": ":/symbols/hub.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "frame_relay_switch"), {"appliance_type": "frame_relay_switch", "name": "Frame Relay switch", "category": 1, "symbol": ":/symbols/frame_relay_switch.svg"}, builtin=True))
|
||||
builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "atm_switch"), {"appliance_type": "atm_switch", "name": "ATM switch", "category": 1, "symbol": ":/symbols/atm_switch.svg"}, builtin=True))
|
||||
|
||||
#FIXME: disable TraceNG
|
||||
#if sys.platform.startswith("win"):
|
||||
# builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "traceng"), {"node_type": "traceng", "name": "TraceNG", "default_name_format": "TraceNG-{0}", "category": 2, "symbol": ":/symbols/traceng.svg", "properties": {}}, builtin=True))
|
||||
# builtins.append(Appliance(uuid.uuid3(uuid.NAMESPACE_DNS, "traceng"), {"appliance_type": "traceng", "name": "TraceNG", "default_name_format": "TraceNG-{0}", "category": 2, "symbol": ":/symbols/traceng.svg", "properties": {}}, builtin=True))
|
||||
for b in builtins:
|
||||
self._appliances[b.id] = b
|
||||
|
||||
@ -464,37 +467,37 @@ class Controller:
|
||||
|
||||
vms = []
|
||||
for vm in settings.get("Qemu", {}).get("vms", []):
|
||||
vm["node_type"] = "qemu"
|
||||
vm["appliance_type"] = "qemu"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("IOU", {}).get("devices", []):
|
||||
vm["node_type"] = "iou"
|
||||
vm["appliance_type"] = "iou"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("Docker", {}).get("containers", []):
|
||||
vm["node_type"] = "docker"
|
||||
vm["appliance_type"] = "docker"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("Builtin", {}).get("cloud_nodes", []):
|
||||
vm["node_type"] = "cloud"
|
||||
vm["appliance_type"] = "cloud"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("Builtin", {}).get("ethernet_switches", []):
|
||||
vm["node_type"] = "ethernet_switch"
|
||||
vm["appliance_type"] = "ethernet_switch"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("Builtin", {}).get("ethernet_hubs", []):
|
||||
vm["node_type"] = "ethernet_hub"
|
||||
vm["appliance_type"] = "ethernet_hub"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("Dynamips", {}).get("routers", []):
|
||||
vm["node_type"] = "dynamips"
|
||||
vm["appliance_type"] = "dynamips"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("VMware", {}).get("vms", []):
|
||||
vm["node_type"] = "vmware"
|
||||
vm["appliance_type"] = "vmware"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("VirtualBox", {}).get("vms", []):
|
||||
vm["node_type"] = "virtualbox"
|
||||
vm["appliance_type"] = "virtualbox"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("VPCS", {}).get("nodes", []):
|
||||
vm["node_type"] = "vpcs"
|
||||
vm["appliance_type"] = "vpcs"
|
||||
vms.append(vm)
|
||||
for vm in settings.get("TraceNG", {}).get("nodes", []):
|
||||
vm["node_type"] = "traceng"
|
||||
vm["appliance_type"] = "traceng"
|
||||
vms.append(vm)
|
||||
|
||||
for vm in vms:
|
||||
|
@ -56,8 +56,12 @@ class Appliance:
|
||||
if "server" in self._settings:
|
||||
self._settings["compute_id"] = self._settings.pop("server")
|
||||
|
||||
# The "node_type" setting has been replaced by "appliance_type" setting in version 2.2
|
||||
if "node_type" in self._settings:
|
||||
self._settings["appliance_type"] = self._settings.pop("node_type")
|
||||
|
||||
# Remove an old IOU setting
|
||||
if settings["node_type"] == "iou" and "image" in settings:
|
||||
if self._settings["appliance_type"] == "iou" and "image" in self._settings:
|
||||
del self._settings["image"]
|
||||
|
||||
self._builtin = builtin
|
||||
@ -72,7 +76,6 @@ class Appliance:
|
||||
|
||||
@settings.setter
|
||||
def settings(self, settings):
|
||||
|
||||
self._settings.update(settings)
|
||||
|
||||
@property
|
||||
@ -84,17 +87,21 @@ class Appliance:
|
||||
return self._settings["compute_id"]
|
||||
|
||||
@property
|
||||
def node_type(self):
|
||||
return self._settings["node_type"]
|
||||
def appliance_type(self):
|
||||
return self._settings["appliance_type"]
|
||||
|
||||
@property
|
||||
def builtin(self):
|
||||
return self._builtin
|
||||
|
||||
def update(self, **kwargs):
|
||||
self._settings.update(kwargs)
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Appliance settings.
|
||||
"""
|
||||
|
||||
settings = self._settings
|
||||
settings.update({"appliance_id": self._id,
|
||||
"default_name_format": settings.get("default_name_format", "{name}-{0}"),
|
||||
|
@ -465,14 +465,14 @@ class Project:
|
||||
Create a node from an appliance
|
||||
"""
|
||||
try:
|
||||
template = self.controller.appliances[appliance_id].settings
|
||||
template = copy.deepcopy(self.controller.appliances[appliance_id].settings)
|
||||
except KeyError:
|
||||
msg = "Appliance {} doesn't exist".format(appliance_id)
|
||||
log.error(msg)
|
||||
raise aiohttp.web.HTTPNotFound(text=msg)
|
||||
template["x"] = x
|
||||
template["y"] = y
|
||||
node_type = template.pop("node_type")
|
||||
node_type = template.pop("appliance_type")
|
||||
compute = self.controller.get_compute(template.pop("compute_id", compute_id))
|
||||
name = template.pop("name")
|
||||
default_name_format = template.pop("default_name_format", "{name}-{0}")
|
||||
|
@ -20,6 +20,9 @@ from gns3server.controller import Controller
|
||||
from gns3server.schemas.node import NODE_OBJECT_SCHEMA
|
||||
from gns3server.schemas.appliance import APPLIANCE_USAGE_SCHEMA
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
from gns3server.schemas.appliance import (
|
||||
APPLIANCE_OBJECT_SCHEMA,
|
||||
APPLIANCE_UPDATE_SCHEMA,
|
||||
@ -74,10 +77,17 @@ class ApplianceHandler:
|
||||
output=APPLIANCE_OBJECT_SCHEMA)
|
||||
def get(request, response):
|
||||
|
||||
request_etag = request.headers.get("If-None-Match", "")
|
||||
controller = Controller.instance()
|
||||
appliance = controller.get_appliance(request.match_info["appliance_id"])
|
||||
response.set_status(200)
|
||||
response.json(appliance)
|
||||
data = json.dumps(appliance.__json__())
|
||||
appliance_etag = '"' + hashlib.md5(data.encode()).hexdigest() + '"'
|
||||
if appliance_etag == request_etag:
|
||||
response.set_status(304)
|
||||
else:
|
||||
response.headers["ETag"] = appliance_etag
|
||||
response.set_status(200)
|
||||
response.json(appliance)
|
||||
|
||||
@Route.put(
|
||||
r"/appliances/{appliance_id}",
|
||||
@ -93,8 +103,7 @@ class ApplianceHandler:
|
||||
|
||||
controller = Controller.instance()
|
||||
appliance = controller.get_appliance(request.match_info["appliance_id"])
|
||||
#TODO: update appliance!
|
||||
#appliance.settings = request.json
|
||||
appliance.update(**request.json)
|
||||
response.set_status(200)
|
||||
response.json(appliance)
|
||||
|
||||
@ -123,8 +132,6 @@ class ApplianceHandler:
|
||||
})
|
||||
def list(request, response):
|
||||
|
||||
#old_etag = request.headers.get('If-None-Match', '')
|
||||
#print("ETAG => ", old_etag)
|
||||
controller = Controller.instance()
|
||||
response.json([c for c in controller.appliances.values()])
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
import copy
|
||||
from .node import NODE_TYPE_SCHEMA
|
||||
|
||||
APPLIANCE_TYPE_SCHEMA = NODE_TYPE_SCHEMA
|
||||
|
||||
APPLIANCE_OBJECT_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
@ -35,7 +36,7 @@ APPLIANCE_OBJECT_SCHEMA = {
|
||||
"description": "Compute identifier",
|
||||
"type": "string"
|
||||
},
|
||||
"node_type": NODE_TYPE_SCHEMA,
|
||||
"appliance_type": APPLIANCE_TYPE_SCHEMA,
|
||||
"name": {
|
||||
"description": "Appliance name",
|
||||
"type": "string",
|
||||
@ -53,7 +54,7 @@ APPLIANCE_OBJECT_SCHEMA = {
|
||||
},
|
||||
},
|
||||
"additionalProperties": True, #TODO: validate all properties
|
||||
"required": ["appliance_id", "compute_id", "node_type", "name", "default_name_format", "symbol"]
|
||||
"required": ["appliance_id", "compute_id", "appliance_type", "name", "default_name_format", "symbol"]
|
||||
}
|
||||
|
||||
APPLIANCE_CREATE_SCHEMA = copy.deepcopy(APPLIANCE_OBJECT_SCHEMA)
|
||||
@ -62,7 +63,9 @@ APPLIANCE_CREATE_SCHEMA["required"].remove("appliance_id")
|
||||
APPLIANCE_CREATE_SCHEMA["required"].remove("compute_id")
|
||||
APPLIANCE_CREATE_SCHEMA["required"].remove("default_name_format")
|
||||
APPLIANCE_CREATE_SCHEMA["required"].remove("symbol")
|
||||
APPLIANCE_UPDATE_SCHEMA = copy.deepcopy(APPLIANCE_OBJECT_SCHEMA)
|
||||
APPLIANCE_UPDATE_SCHEMA = copy.deepcopy(APPLIANCE_CREATE_SCHEMA)
|
||||
#APPLIANCE_UPDATE_SCHEMA["additionalProperties"] = False
|
||||
del APPLIANCE_UPDATE_SCHEMA["required"]
|
||||
|
||||
APPLIANCE_USAGE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
|
Loading…
Reference in New Issue
Block a user