json-schema validations.

NIO creation refactoring.
pull/11/head
grossmj 10 years ago
parent 2ebac2f20a
commit 9be5625c38

@ -26,6 +26,8 @@ import multiprocessing
import zmq import zmq
import signal import signal
from jsonschema import validate, ValidationError
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -238,6 +240,30 @@ class IModule(multiprocessing.Process):
string=str(e), string=str(e),
tb=tb)) tb=tb))
def validate_request(self, request, schema):
"""
Validates a request.
:param request: request (JSON-RPC params)
:param schema: JSON-SCHEMA to validate the request
:returns: True or False
"""
# check if we have a request
if request == None:
self.send_param_error()
return False
log.debug("received request {}".format(request))
# validate the request
try:
validate(request, schema)
except ValidationError as e:
self.send_custom_error("request validation error: {}".format(e))
return False
return True
def destinations(self): def destinations(self):
""" """
Destinations handled by this module. Destinations handled by this module.

@ -154,6 +154,22 @@ class Dynamips(IModule):
self.send_notification("{}.dynamips_stopped".format(self.name), notification) self.send_notification("{}.dynamips_stopped".format(self.name), notification)
hypervisor.stop() hypervisor.stop()
def get_device_instance(self, device_id, instance_dict):
"""
Returns a device instance.
:param device_id: device identifier
:param instance_dict: dictionary containing the instances
:returns: device instance
"""
if device_id not in instance_dict:
log.debug("device ID {} doesn't exist".format(device_id), exc_info=1)
self.send_custom_error("Device ID {} doesn't exist".format(device_id))
return None
return instance_dict[device_id]
@IModule.route("dynamips.reset") @IModule.route("dynamips.reset")
def reset(self, request): def reset(self, request):
""" """
@ -309,34 +325,34 @@ class Dynamips(IModule):
#TODO: JSON schema validation #TODO: JSON schema validation
nio = None nio = None
if request["nio"] == "NIO_UDP": if request["nio"]["type"] == "nio_udp":
lport = request["lport"] lport = request["nio"]["lport"]
rhost = request["rhost"] rhost = request["nio"]["rhost"]
rport = request["rport"] rport = request["nio"]["rport"]
nio = NIO_UDP(node.hypervisor, lport, rhost, rport) nio = NIO_UDP(node.hypervisor, lport, rhost, rport)
# elif request["nio"] == "NIO_UDP_Auto": # elif request["nio"] == "nio_udp_auto":
# lhost = request["lhost"] # lhost = request["lhost"]
# lport_start = request["lport_start"] # lport_start = request["lport_start"]
# lport_end = request["lport_end"] # lport_end = request["lport_end"]
# nio = NIO_UDP_auto(node.hypervisor, lhost, lport_start, lport_end) # nio = NIO_UDP_auto(node.hypervisor, lhost, lport_start, lport_end)
elif request["nio"] == "NIO_GenericEthernet": elif request["nio"]["type"] == "nio_generic_ethernet":
ethernet_device = request["ethernet_device"] ethernet_device = request["nio"]["ethernet_device"]
nio = NIO_GenericEthernet(node.hypervisor, ethernet_device) nio = NIO_GenericEthernet(node.hypervisor, ethernet_device)
elif request["nio"] == "NIO_LinuxEthernet": elif request["nio"]["type"] == "nio_linux_ethernet":
ethernet_device = request["ethernet_device"] ethernet_device = request["nio"]["ethernet_device"]
nio = NIO_LinuxEthernet(node.hypervisor, ethernet_device) nio = NIO_LinuxEthernet(node.hypervisor, ethernet_device)
elif request["nio"] == "NIO_TAP": elif request["nio"]["type"] == "nio_tap":
tap_device = request["tap_device"] tap_device = request["nio"]["tap_device"]
nio = NIO_TAP(node.hypervisor, tap_device) nio = NIO_TAP(node.hypervisor, tap_device)
elif request["nio"] == "NIO_UNIX": elif request["nio"]["type"] == "nio_unix":
local_file = request["local_file"] local_file = request["nio"]["local_file"]
remote_file = request["remote_file"] remote_file = request["nio"]["remote_file"]
nio = NIO_UNIX(node.hypervisor, local_file, remote_file) nio = NIO_UNIX(node.hypervisor, local_file, remote_file)
elif request["nio"] == "NIO_VDE": elif request["nio"]["type"] == "nio_vde":
control_file = request["control_file"] control_file = request["nio"]["control_file"]
local_file = request["local_file"] local_file = request["nio"]["local_file"]
nio = NIO_VDE(node.hypervisor, control_file, local_file) nio = NIO_VDE(node.hypervisor, control_file, local_file)
elif request["nio"] == "NIO_Null": elif request["nio"]["type"] == "nio_null":
nio = NIO_Null(node.hypervisor) nio = NIO_Null(node.hypervisor)
return nio return nio
@ -448,8 +464,12 @@ class Dynamips(IModule):
:param request: JSON request :param request: JSON request
""" """
try: response = []
import netifaces if not sys.platform.startswith("win"):
except ImportError: try:
raise DynamipsError("The netifaces module is not installed") import netifaces
self.send_response(netifaces.interfaces()) except ImportError:
self.send_custom_error("The netifaces module is not installed")
return
response = netifaces.interfaces()
self.send_response(response)

@ -20,6 +20,13 @@ from gns3server.modules import IModule
from ..nodes.atm_switch import ATMSwitch from ..nodes.atm_switch import ATMSwitch
from ..dynamips_error import DynamipsError from ..dynamips_error import DynamipsError
from ..schemas.atmsw import ATMSW_CREATE_SCHEMA
from ..schemas.atmsw import ATMSW_DELETE_SCHEMA
from ..schemas.atmsw import ATMSW_UPDATE_SCHEMA
from ..schemas.atmsw import ATMSW_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.atmsw import ATMSW_ADD_NIO_SCHEMA
from ..schemas.atmsw import ATMSW_DELETE_NIO_SCHEMA
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -41,7 +48,10 @@ class ATMSW(object):
:param request: JSON request :param request: JSON request
""" """
#TODO: JSON schema validation for the request # validate the request
if request and not self.validate_request(request, ATMSW_CREATE_SCHEMA):
return
name = None name = None
if request and "name" in request: if request and "name" in request:
name = request["name"] name = request["name"]
@ -71,22 +81,20 @@ class ATMSW(object):
- id (switch identifier) - id (switch identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ATMSW_DELETE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the ATM switch instance
log.debug("received request {}".format(request))
atmsw_id = request["id"] atmsw_id = request["id"]
if atmsw_id not in self._atm_switches: atmsw = self.get_device_instance(atmsw_id, self._atm_switches)
self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id)) if not atmsw:
return return
atmsw = self._atm_switches[atmsw_id]
try: try:
atmsw.delete() atmsw.delete()
@ -95,7 +103,7 @@ class ATMSW(object):
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(True)
@IModule.route("dynamips.atmsw.update") @IModule.route("dynamips.atmsw.update")
def atmsw_update(self, request): def atmsw_update(self, request):
@ -109,32 +117,31 @@ class ATMSW(object):
- name (new switch name) - name (new switch name)
Response parameters: Response parameters:
- same as original request - name if changed
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ATMSW_UPDATE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the ATM switch instance
log.debug("received request {}".format(request)) atmsw = self.get_device_instance(request["id"], self._atm_switches)
atmsw_id = request["id"] if not atmsw:
if atmsw_id not in self._atm_switches:
self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id))
return return
atmsw = self._atm_switches[atmsw_id]
response = {}
# rename the switch if requested # rename the switch if requested
if "name" in request and atmsw.name != request["name"]: if "name" in request and atmsw.name != request["name"]:
try: try:
atmsw.name = request["name"] atmsw.name = request["name"]
response["name"] = atmsw.name
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(response)
@IModule.route("dynamips.atmsw.allocate_udp_port") @IModule.route("dynamips.atmsw.allocate_udp_port")
def atmsw_allocate_udp_port(self, request): def atmsw_allocate_udp_port(self, request):
@ -153,17 +160,14 @@ class ATMSW(object):
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ATMSW_ALLOCATE_UDP_PORT_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the ATM switch instance
log.debug("received request {}".format(request)) atmsw = self.get_device_instance(request["id"], self._atm_switches)
atmsw_id = request["id"] if not atmsw:
if atmsw_id not in self._atm_switches:
self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id))
return return
atmsw = self._atm_switches[atmsw_id]
try: try:
# allocate a new UDP port # allocate a new UDP port
@ -185,42 +189,39 @@ class ATMSW(object):
- port (port identifier) - port (port identifier)
- port_id (port identifier) - port_id (port identifier)
- mappings (VCs/VPs mapped to the port) - mappings (VCs/VPs mapped to the port)
- nio (nio type, one of the following) - nio (one of the following)
- "NIO_UDP" - type "nio_udp"
- lport (local port) - lport (local port)
- rhost (remote host) - rhost (remote host)
- rport (remote port) - rport (remote port)
- "NIO_GenericEthernet" - type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_LinuxEthernet" - type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_TAP" - type "nio_tap"
- tap_device (TAP device name e.g. tap0) - tap_device (TAP device name e.g. tap0)
- "NIO_UNIX" - type "nio_unix"
- local_file (path to UNIX socket file) - local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file) - remote_file (path to UNIX socket file)
- "NIO_VDE" - type "nio_vde"
- control_file (path to VDE control file) - control_file (path to VDE control file)
- local_file (path to VDE local file) - local_file (path to VDE local file)
- "NIO_Null" - type "nio_null"
Response parameters: Response parameters:
- same as original request - port_id (unique port identifier)
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ATMSW_ADD_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the ATM switch instance
log.debug("received request {}".format(request)) atmsw = self.get_device_instance(request["id"], self._atm_switches)
atmsw_id = request["id"] if not atmsw:
if atmsw_id not in self._atm_switches:
self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id))
return return
atmsw = self._atm_switches[atmsw_id]
port = request["port"] port = request["port"]
mappings = request["mappings"] mappings = request["mappings"]
@ -261,8 +262,7 @@ class ATMSW(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response({"port_id": request["port_id"]})
self.send_response(request)
@IModule.route("dynamips.atmsw.delete_nio") @IModule.route("dynamips.atmsw.delete_nio")
def atmsw_delete_nio(self, request): def atmsw_delete_nio(self, request):
@ -274,24 +274,21 @@ class ATMSW(object):
- port (port identifier) - port (port identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ATMSW_DELETE_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the ATM switch instance
log.debug("received request {}".format(request)) atmsw = self.get_device_instance(request["id"], self._atm_switches)
atmsw_id = request["id"] if not atmsw:
if atmsw_id not in self._atm_switches:
self.send_custom_error("ATM switch id {} doesn't exist".format(atmsw_id))
return return
atmsw = self._atm_switches[atmsw_id]
port = request["port"]
port = request["port"]
try: try:
for source, destination in atmsw.mapping.copy().items(): for source, destination in atmsw.mapping.copy().items():
if len(source) == 3 and len(destination) == 3: if len(source) == 3 and len(destination) == 3:
@ -315,5 +312,4 @@ class ATMSW(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response(True)
self.send_response(request)

@ -19,6 +19,13 @@ from gns3server.modules import IModule
from ..nodes.hub import Hub from ..nodes.hub import Hub
from ..dynamips_error import DynamipsError from ..dynamips_error import DynamipsError
from ..schemas.ethhub import ETHHUB_CREATE_SCHEMA
from ..schemas.ethhub import ETHHUB_DELETE_SCHEMA
from ..schemas.ethhub import ETHHUB_UPDATE_SCHEMA
from ..schemas.ethhub import ETHHUB_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.ethhub import ETHHUB_ADD_NIO_SCHEMA
from ..schemas.ethhub import ETHHUB_DELETE_NIO_SCHEMA
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -40,7 +47,10 @@ class ETHHUB(object):
:param request: JSON request :param request: JSON request
""" """
#TODO: JSON schema validation for the request # validate the request
if request and not self.validate_request(request, ETHHUB_CREATE_SCHEMA):
return
name = None name = None
if request and "name" in request: if request and "name" in request:
name = request["name"] name = request["name"]
@ -70,22 +80,20 @@ class ETHHUB(object):
- id (hub identifier) - id (hub identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHHUB_DELETE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet hub instance
log.debug("received request {}".format(request))
ethhub_id = request["id"] ethhub_id = request["id"]
if ethhub_id not in self._ethernet_hubs: ethhub = self.get_device_instance(ethhub_id, self._ethernet_hubs)
self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id)) if not ethhub:
return return
ethhub = self._ethernet_hubs[ethhub_id]
try: try:
ethhub.delete() ethhub.delete()
@ -108,27 +116,26 @@ class ETHHUB(object):
- name (new hub name) - name (new hub name)
Response parameters: Response parameters:
- same as original request - name if changed
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHHUB_UPDATE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet hub instance
log.debug("received request {}".format(request)) ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
ethhub_id = request["id"] if not ethhub:
if ethhub_id not in self._ethernet_hubs:
self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id))
return return
ethhub = self._ethernet_hubs[ethhub_id]
response = {}
# rename the hub if requested # rename the hub if requested
if "name" in request and ethhub.name != request["name"]: if "name" in request and ethhub.name != request["name"]:
try: try:
ethhub.name = request["name"] ethhub.name = request["name"]
response["name"] = ethhub.name
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
@ -152,17 +159,14 @@ class ETHHUB(object):
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHHUB_ALLOCATE_UDP_PORT_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet hub instance
log.debug("received request {}".format(request)) ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
ethhub_id = request["id"] if not ethhub:
if ethhub_id not in self._ethernet_hubs:
self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id))
return return
ethhub = self._ethernet_hubs[ethhub_id]
try: try:
# allocate a new UDP port # allocate a new UDP port
@ -183,44 +187,41 @@ class ETHHUB(object):
- id (hub identifier) - id (hub identifier)
- port (port identifier) - port (port identifier)
- port_id (port identifier) - port_id (port identifier)
- nio (nio type, one of the following) - nio (one of the following)
- "NIO_UDP" - type "nio_udp"
- lport (local port) - lport (local port)
- rhost (remote host) - rhost (remote host)
- rport (remote port) - rport (remote port)
- "NIO_GenericEthernet" - type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_LinuxEthernet" - type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_TAP" - type "nio_tap"
- tap_device (TAP device name e.g. tap0) - tap_device (TAP device name e.g. tap0)
- "NIO_UNIX" - type "nio_unix"
- local_file (path to UNIX socket file) - local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file) - remote_file (path to UNIX socket file)
- "NIO_VDE" - type "nio_vde"
- control_file (path to VDE control file) - control_file (path to VDE control file)
- local_file (path to VDE local file) - local_file (path to VDE local file)
- "NIO_Null" - type "nio_null"
Response parameters: Response parameters:
- same as original request - port_id (unique port identifier)
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHHUB_ADD_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet hub instance
log.debug("received request {}".format(request)) ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
ethhub_id = request["id"] if not ethhub:
if ethhub_id not in self._ethernet_hubs:
self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id))
return return
ethhub = self._ethernet_hubs[ethhub_id]
port = request["port"]
port = request["port"]
try: try:
nio = self.create_nio(ethhub, request) nio = self.create_nio(ethhub, request)
if not nio: if not nio:
@ -235,8 +236,7 @@ class ETHHUB(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response({"port_id": request["port_id"]})
self.send_response(request)
@IModule.route("dynamips.ethhub.delete_nio") @IModule.route("dynamips.ethhub.delete_nio")
def ethsw_delete_nio(self, request): def ethsw_delete_nio(self, request):
@ -248,24 +248,21 @@ class ETHHUB(object):
- port (port identifier) - port (port identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHHUB_DELETE_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet hub instance
log.debug("received request {}".format(request)) ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
ethhub_id = request["id"] if not ethhub:
if ethhub_id not in self._ethernet_hubs:
self.send_custom_error("Ethernet hub id {} doesn't exist".format(ethhub_id))
return return
ethhub = self._ethernet_hubs[ethhub_id]
port = request["port"]
port = request["port"]
try: try:
nio = ethhub.remove_nio(port) nio = ethhub.remove_nio(port)
nio.delete() nio.delete()
@ -273,5 +270,4 @@ class ETHHUB(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response(True)
self.send_response(request)

@ -19,6 +19,13 @@ from gns3server.modules import IModule
from ..nodes.ethernet_switch import EthernetSwitch from ..nodes.ethernet_switch import EthernetSwitch
from ..dynamips_error import DynamipsError from ..dynamips_error import DynamipsError
from ..schemas.ethsw import ETHSW_CREATE_SCHEMA
from ..schemas.ethsw import ETHSW_DELETE_SCHEMA
from ..schemas.ethsw import ETHSW_UPDATE_SCHEMA
from ..schemas.ethsw import ETHSW_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.ethsw import ETHSW_ADD_NIO_SCHEMA
from ..schemas.ethsw import ETHSW_DELETE_NIO_SCHEMA
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -40,7 +47,10 @@ class ETHSW(object):
:param request: JSON request :param request: JSON request
""" """
#TODO: JSON schema validation for the request # validate the request
if request and not self.validate_request(request, ETHSW_CREATE_SCHEMA):
return
name = None name = None
if request and "name" in request: if request and "name" in request:
name = request["name"] name = request["name"]
@ -70,22 +80,20 @@ class ETHSW(object):
- id (switch identifier) - id (switch identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHSW_DELETE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet switch instance
log.debug("received request {}".format(request))
ethsw_id = request["id"] ethsw_id = request["id"]
if ethsw_id not in self._ethernet_switches: ethsw = self.get_device_instance(ethsw_id, self._ethernet_switches)
self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id)) if not ethsw:
return return
ethsw = self._ethernet_switches[ethsw_id]
try: try:
ethsw.delete() ethsw.delete()
@ -94,7 +102,7 @@ class ETHSW(object):
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(True)
@IModule.route("dynamips.ethsw.update") @IModule.route("dynamips.ethsw.update")
def ethsw_update(self, request): def ethsw_update(self, request):
@ -109,22 +117,19 @@ class ETHSW(object):
- ports (ports settings) - ports (ports settings)
Response parameters: Response parameters:
- same as original request - name if changed
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHSW_UPDATE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet switch instance
log.debug("received request {}".format(request)) ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
ethsw_id = request["id"] if not ethsw:
if ethsw_id not in self._ethernet_switches:
self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id))
return return
ethsw = self._ethernet_switches[ethsw_id]
if "ports" in request: if "ports" in request:
ports = request["ports"] ports = request["ports"]
@ -144,15 +149,17 @@ class ETHSW(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
response = {}
# rename the switch if requested # rename the switch if requested
if "name" in request and ethsw.name != request["name"]: if "name" in request and ethsw.name != request["name"]:
try: try:
ethsw.name = request["name"] ethsw.name = request["name"]
response["name"] = ethsw.name
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(response)
@IModule.route("dynamips.ethsw.allocate_udp_port") @IModule.route("dynamips.ethsw.allocate_udp_port")
def ethsw_allocate_udp_port(self, request): def ethsw_allocate_udp_port(self, request):
@ -171,17 +178,14 @@ class ETHSW(object):
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHSW_ALLOCATE_UDP_PORT_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet switch instance
log.debug("received request {}".format(request)) ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
ethsw_id = request["id"] if not ethsw:
if ethsw_id not in self._ethernet_switches:
self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id))
return return
ethsw = self._ethernet_switches[ethsw_id]
try: try:
# allocate a new UDP port # allocate a new UDP port
@ -204,42 +208,39 @@ class ETHSW(object):
- port_id (port identifier) - port_id (port identifier)
- vlan (vlan identifier) - vlan (vlan identifier)
- port_type ("access", "dot1q" or "qinq") - port_type ("access", "dot1q" or "qinq")
- nio (nio type, one of the following) - nio (one of the following)
- "NIO_UDP" - type "nio_udp"
- lport (local port) - lport (local port)
- rhost (remote host) - rhost (remote host)
- rport (remote port) - rport (remote port)
- "NIO_GenericEthernet" - type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_LinuxEthernet" - type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_TAP" - type "nio_tap"
- tap_device (TAP device name e.g. tap0) - tap_device (TAP device name e.g. tap0)
- "NIO_UNIX" - type "nio_unix"
- local_file (path to UNIX socket file) - local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file) - remote_file (path to UNIX socket file)
- "NIO_VDE" - type "nio_vde"
- control_file (path to VDE control file) - control_file (path to VDE control file)
- local_file (path to VDE local file) - local_file (path to VDE local file)
- "NIO_Null" - type "nio_null"
Response parameters: Response parameters:
- same as original request - port_id (unique port identifier)
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHSW_ADD_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet switch instance
log.debug("received request {}".format(request)) ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
ethsw_id = request["id"] if not ethsw:
if ethsw_id not in self._ethernet_switches:
self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id))
return return
ethsw = self._ethernet_switches[ethsw_id]
port = request["port"] port = request["port"]
vlan = request["vlan"] vlan = request["vlan"]
@ -264,8 +265,7 @@ class ETHSW(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response({"port_id": request["port_id"]})
self.send_response(request)
@IModule.route("dynamips.ethsw.delete_nio") @IModule.route("dynamips.ethsw.delete_nio")
def ethsw_delete_nio(self, request): def ethsw_delete_nio(self, request):
@ -277,24 +277,21 @@ class ETHSW(object):
- port (port identifier) - port (port identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, ETHSW_DELETE_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Ethernet switch instance
log.debug("received request {}".format(request)) ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
ethsw_id = request["id"] if not ethsw:
if ethsw_id not in self._ethernet_switches:
self.send_custom_error("Ethernet switch id {} doesn't exist".format(ethsw_id))
return return
ethsw = self._ethernet_switches[ethsw_id]
port = request["port"]
port = request["port"]
try: try:
nio = ethsw.remove_nio(port) nio = ethsw.remove_nio(port)
nio.delete() nio.delete()
@ -302,5 +299,4 @@ class ETHSW(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response(True)
self.send_response(request)

@ -19,6 +19,13 @@ from gns3server.modules import IModule
from ..nodes.frame_relay_switch import FrameRelaySwitch from ..nodes.frame_relay_switch import FrameRelaySwitch
from ..dynamips_error import DynamipsError from ..dynamips_error import DynamipsError
from ..schemas.frsw import FRSW_CREATE_SCHEMA
from ..schemas.frsw import FRSW_DELETE_SCHEMA
from ..schemas.frsw import FRSW_UPDATE_SCHEMA
from ..schemas.frsw import FRSW_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.frsw import FRSW_ADD_NIO_SCHEMA
from ..schemas.frsw import FRSW_DELETE_NIO_SCHEMA
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -40,7 +47,10 @@ class FRSW(object):
:param request: JSON request :param request: JSON request
""" """
#TODO: JSON schema validation for the request # validate the request
if request and not self.validate_request(request, FRSW_CREATE_SCHEMA):
return
name = None name = None
if request and "name" in request: if request and "name" in request:
name = request["name"] name = request["name"]
@ -70,22 +80,20 @@ class FRSW(object):
- id (switch identifier) - id (switch identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, FRSW_DELETE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Frame relay switch instance
log.debug("received request {}".format(request))
frsw_id = request["id"] frsw_id = request["id"]
if frsw_id not in self._frame_relay_switches: frsw = self.get_device_instance(frsw_id, self._frame_relay_switches)
self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id)) if not frsw:
return return
frsw = self._frame_relay_switches[frsw_id]
try: try:
frsw.delete() frsw.delete()
@ -94,7 +102,8 @@ class FRSW(object):
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request)
self.send_response(True)
@IModule.route("dynamips.frsw.update") @IModule.route("dynamips.frsw.update")
def frsw_update(self, request): def frsw_update(self, request):
@ -108,30 +117,30 @@ class FRSW(object):
- name (new switch name) - name (new switch name)
Response parameters: Response parameters:
- same as original request - name if updated
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, FRSW_UPDATE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Frame relay switch instance
log.debug("received request {}".format(request)) frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
frsw_id = request["id"] if not frsw:
if frsw_id not in self._frame_relay_switches:
self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id))
return return
frsw = self._frame_relay_switches[frsw_id]
response = {}
# rename the switch if requested # rename the switch if requested
if "name" in request and frsw.name != request["name"]: if "name" in request and frsw.name != request["name"]:
try: try:
frsw.name = request["name"] frsw.name = request["name"]
response["name"] = frsw.name
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(request)
@IModule.route("dynamips.frsw.allocate_udp_port") @IModule.route("dynamips.frsw.allocate_udp_port")
@ -151,17 +160,14 @@ class FRSW(object):
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, FRSW_ALLOCATE_UDP_PORT_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Frame relay switch instance
log.debug("received request {}".format(request)) frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
frsw_id = request["id"] if not frsw:
if frsw_id not in self._frame_relay_switches:
self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id))
return return
frsw = self._frame_relay_switches[frsw_id]
try: try:
# allocate a new UDP port # allocate a new UDP port
@ -183,42 +189,39 @@ class FRSW(object):
- port (port identifier) - port (port identifier)
- port_id (port identifier) - port_id (port identifier)
- mappings (VCs mapped to the port) - mappings (VCs mapped to the port)
- nio (nio type, one of the following) - nio (one of the following)
- "NIO_UDP" - type "nio_udp"
- lport (local port) - lport (local port)
- rhost (remote host) - rhost (remote host)
- rport (remote port) - rport (remote port)
- "NIO_GenericEthernet" - type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_LinuxEthernet" - type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_TAP" - type "nio_tap"
- tap_device (TAP device name e.g. tap0) - tap_device (TAP device name e.g. tap0)
- "NIO_UNIX" - type "nio_unix"
- local_file (path to UNIX socket file) - local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file) - remote_file (path to UNIX socket file)
- "NIO_VDE" - type "nio_vde"
- control_file (path to VDE control file) - control_file (path to VDE control file)
- local_file (path to VDE local file) - local_file (path to VDE local file)
- "NIO_Null" - type "nio_null"
Response parameters: Response parameters:
- same as original request - port_id (unique port identifier)
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, FRSW_ADD_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Frame relay switch instance
log.debug("received request {}".format(request)) frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
frsw_id = request["id"] if not frsw:
if frsw_id not in self._frame_relay_switches:
self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id))
return return
frsw = self._frame_relay_switches[frsw_id]
port = request["port"] port = request["port"]
mappings = request["mappings"] mappings = request["mappings"]
@ -246,8 +249,7 @@ class FRSW(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response({"port_id": request["port_id"]})
self.send_response(request)
@IModule.route("dynamips.frsw.delete_nio") @IModule.route("dynamips.frsw.delete_nio")
def frsw_delete_nio(self, request): def frsw_delete_nio(self, request):
@ -259,24 +261,21 @@ class FRSW(object):
- port (port identifier) - port (port identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, FRSW_DELETE_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the Frame relay switch instance
log.debug("received request {}".format(request)) frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
frsw_id = request["id"] if not frsw:
if frsw_id not in self._frame_relay_switches:
self.send_custom_error("Frame relay switch id {} doesn't exist".format(frsw_id))
return return
frsw = self._frame_relay_switches[frsw_id]
port = request["port"]
port = request["port"]
try: try:
# remove the VCs mapped with this port/nio # remove the VCs mapped with this port/nio
for source, destination in frsw.mapping.copy().items(): for source, destination in frsw.mapping.copy().items():
@ -292,5 +291,4 @@ class FRSW(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response(True)
self.send_response(request)

@ -49,6 +49,19 @@ from ..adapters.wic_1enet import WIC_1ENET
from ..adapters.wic_1t import WIC_1T from ..adapters.wic_1t import WIC_1T
from ..adapters.wic_2t import WIC_2T from ..adapters.wic_2t import WIC_2T
from ..schemas.vm import VM_CREATE_SCHEMA
from ..schemas.vm import VM_DELETE_SCHEMA
from ..schemas.vm import VM_START_SCHEMA
from ..schemas.vm import VM_STOP_SCHEMA
from ..schemas.vm import VM_SUSPEND_SCHEMA
from ..schemas.vm import VM_RELOAD_SCHEMA
from ..schemas.vm import VM_UPDATE_SCHEMA
from ..schemas.vm import VM_SAVE_CONFIG_SCHEMA
from ..schemas.vm import VM_IDLEPCS_SCHEMA
from ..schemas.vm import VM_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.vm import VM_ADD_NIO_SCHEMA
from ..schemas.vm import VM_DELETE_NIO_SCHEMA
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -110,13 +123,10 @@ class VM(object):
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_CREATE_SCHEMA):
return return
log.debug("received request {}".format(request))
#TODO: JSON schema validation
name = None name = None
if "name" in request: if "name" in request:
name = request["name"] name = request["name"]
@ -130,6 +140,9 @@ class VM(object):
try: try:
if platform not in PLATFORMS:
raise DynamipsError("Unknown router platform: {}".format(platform))
if not self._hypervisor_manager: if not self._hypervisor_manager:
self.start_hypervisor_manager() self.start_hypervisor_manager()
@ -197,22 +210,20 @@ class VM(object):
- id (vm identifier) - id (vm identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_DELETE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request))
router_id = request["id"] router_id = request["id"]
if router_id not in self._routers: router = self.get_device_instance(router_id, self._routers)
self.send_custom_error("IOS router id {} doesn't exist".format(router_id)) if not router:
return return
router = self._routers[router_id]
try: try:
router.delete() router.delete()
@ -221,7 +232,8 @@ class VM(object):
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request)
self.send_response(True)
@IModule.route("dynamips.vm.start") @IModule.route("dynamips.vm.start")
def vm_start(self, request): def vm_start(self, request):
@ -232,29 +244,26 @@ class VM(object):
- id (vm identifier) - id (vm identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_START_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
router = self._routers[router_id]
try: try:
router.start() router.start()
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(True)
@IModule.route("dynamips.vm.stop") @IModule.route("dynamips.vm.stop")
def vm_stop(self, request): def vm_stop(self, request):
@ -265,29 +274,27 @@ class VM(object):
- id (vm identifier) - id (vm identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_STOP_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
router = self._routers[router_id]
try: try:
router.stop() router.stop()
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request)
self.send_response(True)
@IModule.route("dynamips.vm.suspend") @IModule.route("dynamips.vm.suspend")
def vm_suspend(self, request): def vm_suspend(self, request):
@ -298,29 +305,27 @@ class VM(object):
- id (vm identifier) - id (vm identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_SUSPEND_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
router = self._routers[router_id]
try: try:
router.suspend() router.suspend()
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request)
self.send_response(True)
@IModule.route("dynamips.vm.reload") @IModule.route("dynamips.vm.reload")
def vm_reload(self, request): def vm_reload(self, request):
@ -331,22 +336,20 @@ class VM(object):
- id (vm identifier) - id (vm identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_RELOAD_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
router = self._routers[router_id]
try: try:
if router.get_status() != "inactive": if router.get_status() != "inactive":
router.stop() router.stop()
@ -354,7 +357,8 @@ class VM(object):
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request)
self.send_response(True)
@IModule.route("dynamips.vm.update") @IModule.route("dynamips.vm.update")
def vm_update(self, request): def vm_update(self, request):
@ -370,37 +374,35 @@ class VM(object):
- private_config_base64 (private-config base64 encoded) - private_config_base64 (private-config base64 encoded)
Response parameters: Response parameters:
- same as original request - updated settings
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_UPDATE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
router = self._routers[router_id]
response = {}
try: try:
# a new startup-config has been pushed # a new startup-config has been pushed
if "startup_config_base64" in request: if "startup_config_base64" in request:
config_filename = "{}.cfg".format(router.name) config_filename = "{}.cfg".format(router.name)
request["startup_config"] = self.save_base64config(request["startup_config_base64"], router, config_filename) response["startup_config"] = self.save_base64config(request["startup_config_base64"], router, config_filename)
if "startup_config" in request: if "startup_config" in response:
router.set_config(request["startup_config"]) router.set_config(response["startup_config"])
# a new private-config has been pushed # a new private-config has been pushed
if "private_config_base64" in request: if "private_config_base64" in request:
config_filename = "{}-private.cfg".format(router.name) config_filename = "{}-private.cfg".format(router.name)
request["private_config"] = self.save_base64config(request["private_config_base64"], router, config_filename) response["private_config"] = self.save_base64config(request["private_config_base64"], router, config_filename)
if "private_config" in request: if "private_config" in response:
router.set_config(router.startup_config, request["private_config"]) router.set_config(router.startup_config, response["private_config"])
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
@ -411,6 +413,7 @@ class VM(object):
if hasattr(router, name) and getattr(router, name) != value: if hasattr(router, name) and getattr(router, name) != value:
try: try:
setattr(router, name, value) setattr(router, name, value)
response[name] = value
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
@ -422,6 +425,7 @@ class VM(object):
if router.slots[slot_id] and type(router.slots[slot_id]) != type(adapter): if router.slots[slot_id] and type(router.slots[slot_id]) != type(adapter):
router.slot_remove_binding(slot_id) router.slot_remove_binding(slot_id)
router.slot_add_binding(slot_id, adapter) router.slot_add_binding(slot_id, adapter)
response[name] = value
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
@ -430,6 +434,7 @@ class VM(object):
if router.slots[slot_id]: if router.slots[slot_id]:
try: try:
router.slot_remove_binding(slot_id) router.slot_remove_binding(slot_id)
response[name] = value
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
@ -441,6 +446,7 @@ class VM(object):
if router.slots[0].wics[wic_slot_id] and type(router.slots[0].wics[wic_slot_id]) != type(wic): if router.slots[0].wics[wic_slot_id] and type(router.slots[0].wics[wic_slot_id]) != type(wic):
router.uninstall_wic(wic_slot_id) router.uninstall_wic(wic_slot_id)
router.install_wic(wic_slot_id, wic) router.install_wic(wic_slot_id, wic)
response[name] = value
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
@ -449,6 +455,7 @@ class VM(object):
if router.slots[0].wics and router.slots[0].wics[wic_slot_id]: if router.slots[0].wics and router.slots[0].wics[wic_slot_id]:
try: try:
router.uninstall_wic(wic_slot_id) router.uninstall_wic(wic_slot_id)
response[name] = value
except DynamipsError as e: except DynamipsError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
@ -457,8 +464,7 @@ class VM(object):
if self._hypervisor_manager.ghost_ios_support: if self._hypervisor_manager.ghost_ios_support:
self.set_ghost_ios(router) self.set_ghost_ios(router)
# for now send back the original request self.send_response(response)
self.send_response(request)
@IModule.route("dynamips.vm.save_config") @IModule.route("dynamips.vm.save_config")
def vm_save_config(self, request): def vm_save_config(self, request):
@ -469,17 +475,14 @@ class VM(object):
- id (vm identifier) - id (vm identifier)
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_SAVE_CONFIG_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
router = self._routers[router_id]
try: try:
if router.startup_config or router.private_config: if router.startup_config or router.private_config:
@ -528,17 +531,14 @@ class VM(object):
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_IDLEPCS_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
router = self._routers[router_id]
try: try:
if "compute" in request and request["compute"] == False: if "compute" in request and request["compute"] == False:
@ -551,7 +551,7 @@ class VM(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
response = {"id": router_id, response = {"id": router.id,
"idlepcs": idlepcs} "idlepcs": idlepcs}
self.send_response(response) self.send_response(response)
@ -571,17 +571,14 @@ class VM(object):
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_ALLOCATE_UDP_PORT_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
router = self._routers[router_id]
try: try:
# allocate a new UDP port # allocate a new UDP port
@ -603,46 +600,42 @@ class VM(object):
- slot (slot number) - slot (slot number)
- port (port number) - port (port number)
- port_id (unique port identifier) - port_id (unique port identifier)
- nio (nio type, one of the following) - nio (one of the following)
- "NIO_UDP" - type "nio_udp"
- lport (local port) - lport (local port)
- rhost (remote host) - rhost (remote host)
- rport (remote port) - rport (remote port)
- "NIO_GenericEthernet" - type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_LinuxEthernet" - type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_TAP" - type "nio_tap"
- tap_device (TAP device name e.g. tap0) - tap_device (TAP device name e.g. tap0)
- "NIO_UNIX" - type "nio_unix"
- local_file (path to UNIX socket file) - local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file) - remote_file (path to UNIX socket file)
- "NIO_VDE" - type "nio_vde"
- control_file (path to VDE control file) - control_file (path to VDE control file)
- local_file (path to VDE local file) - local_file (path to VDE local file)
- "NIO_Null" - type "nio_null"
Response parameters: Response parameters:
- same as original request - port_id (unique port identifier)
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_ADD_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
router = self._routers[router_id]
slot = request["slot"] slot = request["slot"]
port = request["port"] port = request["port"]
try: try:
nio = self.create_nio(router, request) nio = self.create_nio(router, request)
if not nio: if not nio:
@ -657,8 +650,7 @@ class VM(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response({"port_id": request["port_id"]})
self.send_response(request)
@IModule.route("dynamips.vm.delete_nio") @IModule.route("dynamips.vm.delete_nio")
def vm_delete_nio(self, request): def vm_delete_nio(self, request):
@ -671,25 +663,22 @@ class VM(object):
- port (port identifier) - port (port identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, VM_DELETE_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the router instance
log.debug("received request {}".format(request)) router = self.get_device_instance(request["id"], self._routers)
router_id = request["id"] if not router:
router = self._routers[router_id]
if router_id not in self._routers:
self.send_custom_error("IOS router id {} doesn't exist".format(router_id))
return return
slot = request["slot"] slot = request["slot"]
port = request["port"] port = request["port"]
try: try:
nio = router.slot_remove_nio_binding(slot, port) nio = router.slot_remove_nio_binding(slot, port)
nio.delete() nio.delete()
@ -697,5 +686,4 @@ class VM(object):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response(True)
self.send_response(request)

@ -0,0 +1,259 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
ATMSW_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new ATM switch instance",
"type": "object",
"properties": {
"name": {
"description": "ATM switch name",
"type": "string",
"minLength": 1,
}
}
}
ATMSW_DELETE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete an ATM switch instance",
"type": "object",
"properties": {
"id": {
"description": "ATM switch instance ID",
"type": "integer"
},
},
"required": ["id"]
}
ATMSW_UPDATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to update an ATM switch instance",
"type": "object",
"properties": {
"id": {
"description": "ATM switch instance ID",
"type": "integer"
},
"name": {
"description": "ATM switch name",
"type": "string",
"minLength": 1,
},
},
"required": ["id"]
}
ATMSW_ALLOCATE_UDP_PORT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to allocate an UDP port for an ATM switch instance",
"type": "object",
"properties": {
"id": {
"description": "ATM switch instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the ATM switch instance",
"type": "integer"
},
},
"required": ["id", "port_id"]
}
ATMSW_ADD_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to add a NIO for an ATM switch instance",
"type": "object",
"definitions": {
"UDP": {
"description": "UDP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_udp"]
},
"lport": {
"description": "Local port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"rhost": {
"description": "Remote host",
"type": "string",
"minLength": 1
},
"rport": {
"description": "Remote port",
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"required": ["type", "lport", "rhost", "rport"],
"additionalProperties": False
},
"Ethernet": {
"description": "Generic Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_generic_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"LinuxEthernet": {
"description": "Linux Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_linux_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"TAP": {
"description": "TAP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_tap"]
},
"tap_device": {
"description": "TAP device name e.g. tap0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "tap_device"],
"additionalProperties": False
},
"UNIX": {
"description": "UNIX Network Input/Output",
"properties": {
"type": {
"enum": ["nio_unix"]
},
"local_file": {
"description": "path to the UNIX socket file (local)",
"type": "string",
"minLength": 1
},
"remote_file": {
"description": "path to the UNIX socket file (remote)",
"type": "string",
"minLength": 1
},
},
"required": ["type", "local_file", "remote_file"],
"additionalProperties": False
},
"VDE": {
"description": "VDE Network Input/Output",
"properties": {
"type": {
"enum": ["nio_vde"]
},
"control_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
"local_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
},
"required": ["type", "control_file", "local_file"],
"additionalProperties": False
},
"NULL": {
"description": "NULL Network Input/Output",
"properties": {
"type": {
"enum": ["nio_null"]
},
},
"required": ["type"],
"additionalProperties": False
},
},
"properties": {
"id": {
"description": "ATM switch instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the ATM switch instance",
"type": "integer"
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 1,
},
"mappings": {
"type": "object",
},
"nio": {
"type": "object",
"description": "Network Input/Output",
"oneOf": [
{"$ref": "#/definitions/UDP"},
{"$ref": "#/definitions/Ethernet"},
{"$ref": "#/definitions/LinuxEthernet"},
{"$ref": "#/definitions/TAP"},
{"$ref": "#/definitions/UNIX"},
{"$ref": "#/definitions/VDE"},
{"$ref": "#/definitions/NULL"},
]
},
},
"required": ["id", "port", "port_id", "mappings", "nio"],
}
ATMSW_DELETE_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete a NIO for an ATM switch instance",
"type": "object",
"properties": {
"id": {
"description": "ATM switch instance ID",
"type": "integer"
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 1,
},
},
"required": ["id", "port"]
}

@ -0,0 +1,256 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
ETHHUB_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new Ethernet hub instance",
"type": "object",
"properties": {
"name": {
"description": "Ethernet hub name",
"type": "string",
"minLength": 1,
}
}
}
ETHHUB_DELETE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete an Ethernet hub instance",
"type": "object",
"properties": {
"id": {
"description": "Ethernet hub instance ID",
"type": "integer"
},
},
"required": ["id"]
}
ETHHUB_UPDATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to update an Ethernet hub instance",
"type": "object",
"properties": {
"id": {
"description": "Ethernet hub instance ID",
"type": "integer"
},
"name": {
"description": "Ethernet hub name",
"type": "string",
"minLength": 1,
},
},
"required": ["id"]
}
ETHHUB_ALLOCATE_UDP_PORT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to allocate an UDP port for an Ethernet hub instance",
"type": "object",
"properties": {
"id": {
"description": "Ethernet hub instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the Ethernet hub instance",
"type": "integer"
},
},
"required": ["id", "port_id"]
}
ETHHUB_ADD_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to add a NIO for an Ethernet hub instance",
"type": "object",
"definitions": {
"UDP": {
"description": "UDP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_udp"]
},
"lport": {
"description": "Local port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"rhost": {
"description": "Remote host",
"type": "string",
"minLength": 1
},
"rport": {
"description": "Remote port",
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"required": ["type", "lport", "rhost", "rport"],
"additionalProperties": False
},
"Ethernet": {
"description": "Generic Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_generic_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"LinuxEthernet": {
"description": "Linux Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_linux_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"TAP": {
"description": "TAP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_tap"]
},
"tap_device": {
"description": "TAP device name e.g. tap0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "tap_device"],
"additionalProperties": False
},
"UNIX": {
"description": "UNIX Network Input/Output",
"properties": {
"type": {
"enum": ["nio_unix"]
},
"local_file": {
"description": "path to the UNIX socket file (local)",
"type": "string",
"minLength": 1
},
"remote_file": {
"description": "path to the UNIX socket file (remote)",
"type": "string",
"minLength": 1
},
},
"required": ["type", "local_file", "remote_file"],
"additionalProperties": False
},
"VDE": {
"description": "VDE Network Input/Output",
"properties": {
"type": {
"enum": ["nio_vde"]
},
"control_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
"local_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
},
"required": ["type", "control_file", "local_file"],
"additionalProperties": False
},
"NULL": {
"description": "NULL Network Input/Output",
"properties": {
"type": {
"enum": ["nio_null"]
},
},
"required": ["type"],
"additionalProperties": False
},
},
"properties": {
"id": {
"description": "Ethernet hub instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the Ethernet hub instance",
"type": "integer"
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 1,
},
"nio": {
"type": "object",
"description": "Network Input/Output",
"oneOf": [
{"$ref": "#/definitions/UDP"},
{"$ref": "#/definitions/Ethernet"},
{"$ref": "#/definitions/LinuxEthernet"},
{"$ref": "#/definitions/TAP"},
{"$ref": "#/definitions/UNIX"},
{"$ref": "#/definitions/VDE"},
{"$ref": "#/definitions/NULL"},
]
},
},
"required": ["id", "port_id", "port", "nio"]
}
ETHHUB_DELETE_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete a NIO for an Ethernet hub instance",
"type": "object",
"properties": {
"id": {
"description": "Ethernet hub instance ID",
"type": "integer"
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 1,
},
},
"required": ["id", "port"]
}

@ -0,0 +1,285 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
ETHSW_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new Ethernet switch instance",
"type": "object",
"properties": {
"name": {
"description": "Ethernet switch name",
"type": "string",
"minLength": 1,
}
}
}
ETHSW_DELETE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete an Ethernet switch instance",
"type": "object",
"properties": {
"id": {
"description": "Ethernet switch instance ID",
"type": "integer"
},
},
"required": ["id"]
}
#TODO: ports {'1': {'vlan': 1, 'type': 'qinq'}
ETHSW_UPDATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to update an Ethernet switch instance",
"type": "object",
"properties": {
"id": {
"description": "Ethernet switch instance ID",
"type": "integer"
},
"name": {
"description": "Ethernet switch name",
"type": "string",
"minLength": 1,
},
# "ports": {
# "type": "object",
# "properties": {
# "type": {
# "description": "Port type",
# "enum": ["access", "dot1q", "qinq"],
# },
# "vlan": {
# "description": "VLAN number",
# "type": "integer",
# "minimum": 1
# },
# },
# },
},
"required": ["id"]
}
ETHSW_ALLOCATE_UDP_PORT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to allocate an UDP port for an Ethernet switch instance",
"type": "object",
"properties": {
"id": {
"description": "Ethernet switch instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the Ethernet switch instance",
"type": "integer"
},
},
"required": ["id", "port_id"]
}
ETHSW_ADD_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to add a NIO for an Ethernet switch instance",
"type": "object",
"definitions": {
"UDP": {
"description": "UDP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_udp"]
},
"lport": {
"description": "Local port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"rhost": {
"description": "Remote host",
"type": "string",
"minLength": 1
},
"rport": {
"description": "Remote port",
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"required": ["type", "lport", "rhost", "rport"],
"additionalProperties": False
},
"Ethernet": {
"description": "Generic Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_generic_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"LinuxEthernet": {
"description": "Linux Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_linux_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"TAP": {
"description": "TAP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_tap"]
},
"tap_device": {
"description": "TAP device name e.g. tap0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "tap_device"],
"additionalProperties": False
},
"UNIX": {
"description": "UNIX Network Input/Output",
"properties": {
"type": {
"enum": ["nio_unix"]
},
"local_file": {
"description": "path to the UNIX socket file (local)",
"type": "string",
"minLength": 1
},
"remote_file": {
"description": "path to the UNIX socket file (remote)",
"type": "string",
"minLength": 1
},
},
"required": ["type", "local_file", "remote_file"],
"additionalProperties": False
},
"VDE": {
"description": "VDE Network Input/Output",
"properties": {
"type": {
"enum": ["nio_vde"]
},
"control_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
"local_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
},
"required": ["type", "control_file", "local_file"],
"additionalProperties": False
},
"NULL": {
"description": "NULL Network Input/Output",
"properties": {
"type": {
"enum": ["nio_null"]
},
},
"required": ["type"],
"additionalProperties": False
},
},
"properties": {
"id": {
"description": "Ethernet switch instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the Ethernet switch instance",
"type": "integer"
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 1,
},
"port_type": {
"description": "Port type",
"enum": ["access", "dot1q", "qinq"],
},
"vlan": {
"description": "VLAN number",
"type": "integer",
"minimum": 1
},
"nio": {
"type": "object",
"description": "Network Input/Output",
"oneOf": [
{"$ref": "#/definitions/UDP"},
{"$ref": "#/definitions/Ethernet"},
{"$ref": "#/definitions/LinuxEthernet"},
{"$ref": "#/definitions/TAP"},
{"$ref": "#/definitions/UNIX"},
{"$ref": "#/definitions/VDE"},
{"$ref": "#/definitions/NULL"},
]
},
},
"required": ["id", "port_id", "port", "port_type", "vlan", "nio"],
"dependencies": {
"port_type": ["vlan"],
"vlan": ["port_type"]
}
}
ETHSW_DELETE_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete a NIO for an Ethernet switch instance",
"type": "object",
"properties": {
"id": {
"description": "Ethernet switch instance ID",
"type": "integer"
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 1,
},
},
"required": ["id", "port"]
}

@ -0,0 +1,259 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
FRSW_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new Frame relay switch instance",
"type": "object",
"properties": {
"name": {
"description": "Frame relay switch name",
"type": "string",
"minLength": 1,
}
}
}
FRSW_DELETE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete a Frame relay switch instance",
"type": "object",
"properties": {
"id": {
"description": "Frame relay switch instance ID",
"type": "integer"
},
},
"required": ["id"]
}
FRSW_UPDATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to update a Frame relay switch instance",
"type": "object",
"properties": {
"id": {
"description": "Frame relay switch instance ID",
"type": "integer"
},
"name": {
"description": "Frame relay switch name",
"type": "string",
"minLength": 1,
},
},
"required": ["id"]
}
FRSW_ALLOCATE_UDP_PORT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to allocate an UDP port for a Frame relay switch instance",
"type": "object",
"properties": {
"id": {
"description": "Frame relay switch instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the Frame relay switch instance",
"type": "integer"
},
},
"required": ["id", "port_id"]
}
FRSW_ADD_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to add a NIO for a Frame relay switch instance",
"type": "object",
"definitions": {
"UDP": {
"description": "UDP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_udp"]
},
"lport": {
"description": "Local port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"rhost": {
"description": "Remote host",
"type": "string",
"minLength": 1
},
"rport": {
"description": "Remote port",
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"required": ["type", "lport", "rhost", "rport"],
"additionalProperties": False
},
"Ethernet": {
"description": "Generic Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_generic_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"LinuxEthernet": {
"description": "Linux Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_linux_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"TAP": {
"description": "TAP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_tap"]
},
"tap_device": {
"description": "TAP device name e.g. tap0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "tap_device"],
"additionalProperties": False
},
"UNIX": {
"description": "UNIX Network Input/Output",
"properties": {
"type": {
"enum": ["nio_unix"]
},
"local_file": {
"description": "path to the UNIX socket file (local)",
"type": "string",
"minLength": 1
},
"remote_file": {
"description": "path to the UNIX socket file (remote)",
"type": "string",
"minLength": 1
},
},
"required": ["type", "local_file", "remote_file"],
"additionalProperties": False
},
"VDE": {
"description": "VDE Network Input/Output",
"properties": {
"type": {
"enum": ["nio_vde"]
},
"control_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
"local_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
},
"required": ["type", "control_file", "local_file"],
"additionalProperties": False
},
"NULL": {
"description": "NULL Network Input/Output",
"properties": {
"type": {
"enum": ["nio_null"]
},
},
"required": ["type"],
"additionalProperties": False
},
},
"properties": {
"id": {
"description": "Frame relay switch instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the Frame relay switch instance",
"type": "integer"
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 1,
},
"mappings": {
"type": "object",
},
"nio": {
"type": "object",
"description": "Network Input/Output",
"oneOf": [
{"$ref": "#/definitions/UDP"},
{"$ref": "#/definitions/Ethernet"},
{"$ref": "#/definitions/LinuxEthernet"},
{"$ref": "#/definitions/TAP"},
{"$ref": "#/definitions/UNIX"},
{"$ref": "#/definitions/VDE"},
{"$ref": "#/definitions/NULL"},
]
},
},
"required": ["id", "port", "port_id", "mappings", "nio"],
}
FRSW_DELETE_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete a NIO for a Frame relay switch instance",
"type": "object",
"properties": {
"id": {
"description": "Frame relay switch instance ID",
"type": "integer"
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 1,
},
},
"required": ["id", "port"]
}

@ -0,0 +1,541 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
VM_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new VM instance",
"type": "object",
"properties": {
"name": {
"description": "Router name",
"type": "string",
"minLength": 1,
},
"platform": {
"description": "router platform",
"type": "string",
"minLength": 1,
"pattern": "^c[0-9]{4}$"
},
"chassis": {
"description": "router chassis model",
"type": "string",
"minLength": 1,
"pattern": "^[0-9]{4}$"
},
"image": {
"description": "path to the IOS image file",
"type": "string",
"minLength": 1
},
"ram": {
"description": "amount of RAM in MB",
"type": "integer"
},
"console": {
"description": "console TCP port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"aux": {
"description": "auxiliary console TCP port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"mac_address": {
"description": "base MAC address",
"type": "string",
"minLength": 1,
"pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$"
}
},
"required": ["platform", "image", "ram"]
}
VM_DELETE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete a VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
},
"required": ["id"]
}
VM_START_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to start a VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
},
"required": ["id"]
}
VM_STOP_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to stop a VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
},
"required": ["id"]
}
VM_SUSPEND_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to suspend a VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
},
"required": ["id"]
}
VM_RELOAD_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to reload a VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
},
"required": ["id"]
}
#TODO: platform specific properties?
VM_UPDATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to update a VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
"name": {
"description": "Router name",
"type": "string",
"minLength": 1,
},
"platform": {
"description": "platform",
"type": "string",
"minLength": 1,
"pattern": "^c[0-9]{4}$"
},
"image": {
"description": "path to the IOS image",
"type": "string",
"minLength": 1,
},
"startup_config": {
"description": "path to the IOS startup configuration file",
"type": "string",
"minLength": 1,
},
"private_config": {
"description": "path to the IOS private configuration file",
"type": "string",
"minLength": 1,
},
"ram": {
"description": "amount of RAM in MB",
"type": "integer"
},
"nvram": {
"description": "amount of NVRAM in KB",
"type": "integer"
},
"mmap": {
"description": "MMAP feature",
"type": "boolean"
},
"sparsemem": {
"description": "sparse memory feature",
"type": "boolean"
},
"clock_divisor": {
"description": "clock divisor",
"type": "integer"
},
"idlepc": {
"description": "idle-pc value",
"type": "string",
"minLength": 1,
"pattern": "^0x[0-9a-fA-F]+$"
},
"idlemax": {
"description": "idlemax value",
"type": "integer",
},
"idlesleep": {
"description": "idlesleep value",
"type": "integer",
},
"exec_area": {
"description": "exec area value",
"type": "integer",
},
"jit_sharing_group": {
"description": "JIT sharing group",
"type": "integer",
},
"disk0": {
"description": "disk0 size in MB",
"type": "integer"
},
"disk1": {
"description": "disk1 size in MB",
"type": "integer"
},
"confreg": {
"description": "configuration register",
"type": "string",
"minLength": 1,
"pattern": "^0x[0-9a-fA-F]{4}$"
},
"console": {
"description": "console TCP port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"aux": {
"description": "auxiliary console TCP port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"mac_address": {
"description": "base MAC address",
"type": "string",
"minLength": 1,
"pattern": "^([0-9a-fA-F]{4}\\.){2}[0-9a-fA-F]{4}$"
},
"system_id": {
"description": "system ID",
"type": "string",
"minLength": 1,
},
"slot0": {
"description": "Network module slot 0",
"type": "string",
},
"slot1": {
"description": "Network module slot 1",
"type": "string",
},
"slot2": {
"description": "Network module slot 2",
"type": "string",
},
"slot3": {
"description": "Network module slot 3",
"type": "string",
},
"slot4": {
"description": "Network module slot 4",
"type": "string",
},
"slot5": {
"description": "Network module slot 5",
"type": "string",
},
"slot6": {
"description": "Network module slot 6",
"type": "string",
},
"wic0": {
"description": "Network module WIC slot 0",
"type": "string",
},
"wic1": {
"description": "Network module WIC slot 0",
"type": "string",
},
"wic2": {
"description": "Network module WIC slot 0",
"type": "string",
},
"startup_config_base64": {
"description": "startup configuration base64 encoded",
"type": "string"
},
"private_config_base64": {
"description": "private configuration base64 encoded",
"type": "string"
},
},
"required": ["id"]
}
VM_SAVE_CONFIG_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to save the configs for VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
},
"required": ["id"]
}
VM_IDLEPCS_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to calculate or show idle-pcs for VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
"compute": {
"description": "indicates to compute new idle-pc values",
"type": "boolean"
},
},
"required": ["id"]
}
VM_ALLOCATE_UDP_PORT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to allocate an UDP port for a VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the VM instance",
"type": "integer"
},
},
"required": ["id", "port_id"]
}
VM_ADD_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to add a NIO for a VM instance",
"type": "object",
"definitions": {
"UDP": {
"description": "UDP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_udp"]
},
"lport": {
"description": "Local port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"rhost": {
"description": "Remote host",
"type": "string",
"minLength": 1
},
"rport": {
"description": "Remote port",
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"required": ["type", "lport", "rhost", "rport"],
"additionalProperties": False
},
"Ethernet": {
"description": "Generic Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_generic_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"LinuxEthernet": {
"description": "Linux Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_linux_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"TAP": {
"description": "TAP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_tap"]
},
"tap_device": {
"description": "TAP device name e.g. tap0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "tap_device"],
"additionalProperties": False
},
"UNIX": {
"description": "UNIX Network Input/Output",
"properties": {
"type": {
"enum": ["nio_unix"]
},
"local_file": {
"description": "path to the UNIX socket file (local)",
"type": "string",
"minLength": 1
},
"remote_file": {
"description": "path to the UNIX socket file (remote)",
"type": "string",
"minLength": 1
},
},
"required": ["type", "local_file", "remote_file"],
"additionalProperties": False
},
"VDE": {
"description": "VDE Network Input/Output",
"properties": {
"type": {
"enum": ["nio_vde"]
},
"control_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
"local_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
},
"required": ["type", "control_file", "local_file"],
"additionalProperties": False
},
"NULL": {
"description": "NULL Network Input/Output",
"properties": {
"type": {
"enum": ["nio_null"]
},
},
"required": ["type"],
"additionalProperties": False
},
},
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the VM instance",
"type": "integer"
},
"slot": {
"description": "Slot number",
"type": "integer",
"minimum": 0,
"maximum": 6
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 0,
"maximum": 15
},
"nio": {
"type": "object",
"description": "Network Input/Output",
"oneOf": [
{"$ref": "#/definitions/UDP"},
{"$ref": "#/definitions/Ethernet"},
{"$ref": "#/definitions/LinuxEthernet"},
{"$ref": "#/definitions/TAP"},
{"$ref": "#/definitions/UNIX"},
{"$ref": "#/definitions/VDE"},
{"$ref": "#/definitions/NULL"},
]
},
},
"required": ["id", "port_id", "slot", "port", "nio"]
}
VM_DELETE_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete a NIO for a VM instance",
"type": "object",
"properties": {
"id": {
"description": "VM instance ID",
"type": "integer"
},
"slot": {
"description": "Slot number",
"type": "integer",
"minimum": 0,
"maximum": 6
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 0,
"maximum": 15
},
},
"required": ["id", "slot", "port"]
}

@ -27,6 +27,7 @@ import fcntl
import struct import struct
import socket import socket
import shutil import shutil
from gns3server.modules import IModule from gns3server.modules import IModule
from gns3server.config import Config from gns3server.config import Config
from .iou_device import IOUDevice from .iou_device import IOUDevice
@ -36,6 +37,16 @@ from .nios.nio_tap import NIO_TAP
from .nios.nio_generic_ethernet import NIO_GenericEthernet from .nios.nio_generic_ethernet import NIO_GenericEthernet
import gns3server.jsonrpc as jsonrpc import gns3server.jsonrpc as jsonrpc
from .schemas import IOU_CREATE_SCHEMA
from .schemas import IOU_DELETE_SCHEMA
from .schemas import IOU_UPDATE_SCHEMA
from .schemas import IOU_START_SCHEMA
from .schemas import IOU_STOP_SCHEMA
from .schemas import IOU_RELOAD_SCHEMA
from .schemas import IOU_ALLOCATE_UDP_PORT_SCHEMA
from .schemas import IOU_ADD_NIO_SCHEMA
from .schemas import IOU_DELETE_NIO_SCHEMA
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -132,6 +143,21 @@ class IOU(IModule):
self.send_notification("{}.iouyap_stopped".format(self.name), notification) self.send_notification("{}.iouyap_stopped".format(self.name), notification)
iou_instance.stop() iou_instance.stop()
def get_iou_instance(self, iou_id):
"""
Returns an IOU device instance.
:param iou_id: IOU device identifier
:returns: IOUDevice instance
"""
if iou_id not in self._iou_instances:
log.debug("IOU device ID {} doesn't exist".format(iou_id), exc_info=1)
self.send_custom_error("IOU device ID {} doesn't exist".format(iou_id))
return None
return self._iou_instances[iou_id]
@IModule.route("iou.reset") @IModule.route("iou.reset")
def reset(self, request): def reset(self, request):
""" """
@ -238,22 +264,27 @@ class IOU(IModule):
""" """
Creates a new IOU instance. Creates a new IOU instance.
Mandatory request parameters:
- path (path to the IOU executable)
Optional request parameters: Optional request parameters:
- name (IOU name) - name (IOU name)
- path (path to the IOU executable)
Response parameters: Response parameters:
- id (IOU instance identifier) - id (IOU instance identifier)
- name (IOU name) - name (IOU name)
- default settings
:param request: JSON request :param request: JSON request
""" """
#TODO: JSON schema validation for the request # validate the request
if not self.validate_request(request, IOU_CREATE_SCHEMA):
return
name = None name = None
if request and "name" in request: if "name" in request:
name = request["name"] name = request["name"]
iou_path = request["path"] iou_path = request["path"]
try: try:
@ -290,31 +321,29 @@ class IOU(IModule):
Mandatory request parameters: Mandatory request parameters:
- id (IOU instance identifier) - id (IOU instance identifier)
Response parameters: Response parameter:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, IOU_DELETE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the instance
log.debug("received request {}".format(request)) iou_instance = self.get_iou_instance(request["id"])
iou_id = request["id"] if not iou_instance:
if iou_id not in self._iou_instances:
self.send_custom_error("IOU device id {} doesn't exist".format(iou_id))
return return
iou_instance = self._iou_instances[iou_id]
try: try:
iou_instance.delete() iou_instance.delete()
del self._iou_instances[iou_id] del self._iou_instances[request["id"]]
except IOUError as e: except IOUError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request)
self.send_response(True)
@IModule.route("iou.update") @IModule.route("iou.update")
def iou_update(self, request): def iou_update(self, request):
@ -329,23 +358,21 @@ class IOU(IModule):
- startup_config_base64 (startup-config base64 encoded) - startup_config_base64 (startup-config base64 encoded)
Response parameters: Response parameters:
- same as original request - updated settings
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, IOU_UPDATE_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the instance
log.debug("received request {}".format(request)) iou_instance = self.get_iou_instance(request["id"])
iou_id = request["id"] if not iou_instance:
if iou_id not in self._iou_instances:
self.send_custom_error("IOU device id {} doesn't exist".format(iou_id))
return return
iou_instance = self._iou_instances[iou_id]
response = {}
try: try:
# a new startup-config has been pushed # a new startup-config has been pushed
if "startup_config_base64" in request: if "startup_config_base64" in request:
@ -359,9 +386,9 @@ class IOU(IModule):
f.write(config) f.write(config)
except OSError as e: except OSError as e:
raise IOUError("Could not save the configuration {}: {}".format(config_path, e)) raise IOUError("Could not save the configuration {}: {}".format(config_path, e))
request["startup_config"] = os.path.basename(config_path) response["startup_config"] = os.path.basename(config_path)
if "startup_config" in request: if "startup_config" in request:
iou_instance.startup_config = request["startup_config"] iou_instance.startup_config = response["startup_config"]
except IOUError as e: except IOUError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
@ -370,11 +397,12 @@ class IOU(IModule):
if hasattr(iou_instance, name) and getattr(iou_instance, name) != value: if hasattr(iou_instance, name) and getattr(iou_instance, name) != value:
try: try:
setattr(iou_instance, name, value) setattr(iou_instance, name, value)
response[name] = value
except IOUError as e: except IOUError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(response)
@IModule.route("iou.start") @IModule.route("iou.start")
def vm_start(self, request): def vm_start(self, request):
@ -385,22 +413,19 @@ class IOU(IModule):
- id (IOU instance identifier) - id (IOU instance identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, IOU_START_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the instance
log.debug("received request {}".format(request)) iou_instance = self.get_iou_instance(request["id"])
iou_id = request["id"] if not iou_instance:
if iou_id not in self._iou_instances:
self.send_custom_error("IOU device id {} doesn't exist".format(iou_id))
return return
iou_instance = self._iou_instances[iou_id]
try: try:
log.debug("starting IOU with command: {}".format(iou_instance.command())) log.debug("starting IOU with command: {}".format(iou_instance.command()))
@ -410,7 +435,7 @@ class IOU(IModule):
except IOUError as e: except IOUError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(True)
@IModule.route("iou.stop") @IModule.route("iou.stop")
def vm_stop(self, request): def vm_stop(self, request):
@ -421,29 +446,26 @@ class IOU(IModule):
- id (IOU instance identifier) - id (IOU instance identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, IOU_STOP_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the instance
log.debug("received request {}".format(request)) iou_instance = self.get_iou_instance(request["id"])
iou_id = request["id"] if not iou_instance:
if iou_id not in self._iou_instances:
self.send_custom_error("IOU device id {} doesn't exist".format(iou_id))
return return
iou_instance = self._iou_instances[iou_id]
try: try:
iou_instance.stop() iou_instance.stop()
except IOUError as e: except IOUError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(True)
@IModule.route("iou.reload") @IModule.route("iou.reload")
def vm_reload(self, request): def vm_reload(self, request):
@ -454,22 +476,19 @@ class IOU(IModule):
- id (IOU identifier) - id (IOU identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, IOU_RELOAD_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the instance
log.debug("received request {}".format(request)) iou_instance = self.get_iou_instance(request["id"])
iou_id = request["id"] if not iou_instance:
if iou_id not in self._iou_instances:
self.send_custom_error("IOU device id {} doesn't exist".format(iou_id))
return return
iou_instance = self._iou_instances[iou_id]
try: try:
if iou_instance.is_running(): if iou_instance.is_running():
@ -478,7 +497,7 @@ class IOU(IModule):
except IOUError as e: except IOUError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
self.send_response(request) self.send_response(True)
@IModule.route("iou.allocate_udp_port") @IModule.route("iou.allocate_udp_port")
def allocate_udp_port(self, request): def allocate_udp_port(self, request):
@ -496,17 +515,14 @@ class IOU(IModule):
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, IOU_ALLOCATE_UDP_PORT_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the instance
log.debug("received request {}".format(request)) iou_instance = self.get_iou_instance(request["id"])
iou_id = request["id"] if not iou_instance:
if iou_id not in self._iou_instances:
self.send_custom_error("IOU device id {} doesn't exist".format(iou_id))
return return
iou_instance = self._iou_instances[iou_id]
try: try:
@ -516,8 +532,8 @@ class IOU(IModule):
port = IOUDevice.find_unused_port(self._current_udp_port, self._udp_end_port_range, host=self._host, socket_type="UDP") port = IOUDevice.find_unused_port(self._current_udp_port, self._udp_end_port_range, host=self._host, socket_type="UDP")
self._current_udp_port += 1 self._current_udp_port += 1
log.info("{} [id={}] has allocated UDP port {} with host {}".format(iou_instance .name, log.info("{} [id={}] has allocated UDP port {} with host {}".format(iou_instance.name,
iou_instance .id, iou_instance.id,
port, port,
self._host)) self._host))
response = {"lport": port} response = {"lport": port}
@ -539,75 +555,48 @@ class IOU(IModule):
- slot (slot number) - slot (slot number)
- port (port number) - port (port number)
- port_id (unique port identifier) - port_id (unique port identifier)
- nio (nio type, one of the following) - nio (one of the following)
- "NIO_UDP" - type "nio_udp"
- lport (local port) - lport (local port)
- rhost (remote host) - rhost (remote host)
- rport (remote port) - rport (remote port)
- "NIO_GenericEthernet" - type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0) - ethernet_device (Ethernet device name e.g. eth0)
- "NIO_TAP" - type "nio_tap"
- tap_device (TAP device name e.g. tap0) - tap_device (TAP device name e.g. tap0)
Response parameters: Response parameters:
- same as original request - port_id (unique port identifier)
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, IOU_ADD_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the instance
log.debug("received request {}".format(request)) iou_instance = self.get_iou_instance(request["id"])
iou_id = request["id"] if not iou_instance:
if iou_id not in self._iou_instances:
self.send_custom_error("IOU device id {} doesn't exist".format(iou_id))
return return
iou_instance = self._iou_instances[iou_id]
slot = request["slot"] slot = request["slot"]
port = request["port"] port = request["port"]
try: try:
nio = None nio = None
if request["nio"] == "NIO_UDP": if request["nio"]["type"] == "nio_udp":
lport = request["lport"] lport = request["nio"]["lport"]
rhost = request["rhost"] rhost = request["nio"]["rhost"]
rport = request["rport"] rport = request["nio"]["rport"]
nio = NIO_UDP(lport, rhost, rport) nio = NIO_UDP(lport, rhost, rport)
elif request["nio"] == "NIO_TAP": elif request["nio"]["type"] == "nio_tap":
tap_device = request["tap_device"] tap_device = request["nio"]["tap_device"]
# # check that we have access to the tap device
# TUNSETIFF = 0x400454ca
# IFF_TAP = 0x0002
# IFF_NO_PI = 0x1000
# try:
# tun = os.open("/dev/net/tun", os.O_RDWR)
# except OSError as e:
# raise IOUError("Could not open /dev/net/tun: {}".format(e))
# ifr = struct.pack("16sH", tap_device.encode("utf-8"), IFF_TAP | IFF_NO_PI)
# try:
# fcntl.ioctl(tun, TUNSETIFF, ifr)
# os.close(tun)
# except IOError as e:
# raise IOUError("TAP NIO {}: {}".format(tap_device, e))
nio = NIO_TAP(tap_device) nio = NIO_TAP(tap_device)
elif request["nio"] == "NIO_GenericEthernet": elif request["nio"]["type"] == "nio_generic_ethernet":
ethernet_device = request["ethernet_device"] ethernet_device = request["nio"]["ethernet_device"]
# # check that we have access to the Ethernet device
# try:
# with socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW):
# pass
# except socket.error as e:
# raise IOUError("Generic Ethernet NIO {}: {}".format(ethernet_device, e))
nio = NIO_GenericEthernet(ethernet_device) nio = NIO_GenericEthernet(ethernet_device)
if not nio: if not nio:
raise IOUError("Requested NIO doesn't exist or is not supported: {}".format(request["nio"])) raise IOUError("Requested NIO does not exist or is not supported: {}".format(request["nio"]["type"]))
except IOUError as e: except IOUError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
@ -618,8 +607,7 @@ class IOU(IModule):
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response({"port_id": request["port_id"]})
self.send_response(request)
@IModule.route("iou.delete_nio") @IModule.route("iou.delete_nio")
def delete_nio(self, request): def delete_nio(self, request):
@ -632,33 +620,29 @@ class IOU(IModule):
- port (port identifier) - port (port identifier)
Response parameters: Response parameters:
- same as original request - True on success
:param request: JSON request :param request: JSON request
""" """
if request == None: # validate the request
self.send_param_error() if not self.validate_request(request, IOU_DELETE_NIO_SCHEMA):
return return
#TODO: JSON schema validation for the request # get the instance
log.debug("received request {}".format(request)) iou_instance = self.get_iou_instance(request["id"])
iou_id = request["id"] if not iou_instance:
iou_instance = self._iou_instances[iou_id]
if iou_id not in self._iou_instances:
self.send_custom_error("IOU device id {} doesn't exist".format(iou_id))
return return
slot = request["slot"] slot = request["slot"]
port = request["port"] port = request["port"]
try: try:
iou_instance.slot_remove_nio_binding(slot, port) iou_instance.slot_remove_nio_binding(slot, port)
except IOUError as e: except IOUError as e:
self.send_custom_error(str(e)) self.send_custom_error(str(e))
return return
# for now send back the original request self.send_response(True)
self.send_response(request)
@IModule.route("iou.echo") @IModule.route("iou.echo")
def echo(self, request): def echo(self, request):

@ -402,8 +402,7 @@ class IOU(Router):
try: try:
self.fd.connect(self.ttyS) self.fd.connect(self.ttyS)
except FileNotFoundError: except FileNotFoundError:
log.debug("Waiting to connect to {}".format(self.ttyS), log.debug("Waiting to connect to {}".format(self.ttyS))
file=sys.stderr)
time.sleep(RETRY_DELAY) time.sleep(RETRY_DELAY)
except Exception as e: except Exception as e:
raise NetioError("Couldn't connect to socket {}: {}" raise NetioError("Couldn't connect to socket {}: {}"

@ -0,0 +1,364 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
IOU_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new IOU instance",
"type": "object",
"properties": {
"name": {
"description": "IOU device name",
"type": "string",
"minLength": 1,
},
"path": {
"description": "path to the IOU executable",
"type": "string",
"minLength": 1,
}
},
"required": ["path"]
}
IOU_DELETE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete an IOU instance",
"type": "object",
"properties": {
"id": {
"description": "IOU device instance ID",
"type": "integer"
},
},
"required": ["id"]
}
IOU_UPDATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to update an IOU instance",
"type": "object",
"properties": {
"id": {
"description": "IOU device instance ID",
"type": "integer"
},
"name": {
"description": "IOU device name",
"type": "string",
"minLength": 1,
},
"path": {
"description": "path to the IOU executable",
"type": "string",
"minLength": 1,
},
"startup_config": {
"description": "path to the IOU startup configuration file",
"type": "string",
"minLength": 1,
},
"ram": {
"description": "amount of RAM in MB",
"type": "integer"
},
"nvram": {
"description": "amount of NVRAM in KB",
"type": "integer"
},
"ethernet_adapters": {
"description": "number of Ethernet adapters",
"type": "integer",
"minimum": 0,
"maximum": 16,
},
"serial_adapters": {
"description": "number of serial adapters",
"type": "integer",
"minimum": 0,
"maximum": 16,
},
"console": {
"description": "console TCP port",
"minimum": 1,
"maximum": 65535,
"type": "integer"
},
"startup_config_base64": {
"description": "startup configuration base64 encoded",
"type": "string"
},
},
"required": ["id"]
}
IOU_START_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to start an IOU instance",
"type": "object",
"properties": {
"id": {
"description": "IOU device instance ID",
"type": "integer"
},
},
"required": ["id"]
}
IOU_STOP_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to stop an IOU instance",
"type": "object",
"properties": {
"id": {
"description": "IOU device instance ID",
"type": "integer"
},
},
"required": ["id"]
}
IOU_RELOAD_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to reload an IOU instance",
"type": "object",
"properties": {
"id": {
"description": "IOU device instance ID",
"type": "integer"
},
},
"required": ["id"]
}
IOU_ALLOCATE_UDP_PORT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to allocate an UDP port for an IOU instance",
"type": "object",
"properties": {
"id": {
"description": "IOU device instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the IOU instance",
"type": "integer"
},
},
"required": ["id", "port_id"]
}
IOU_ADD_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to add a NIO for an IOU instance",
"type": "object",
"definitions": {
"UDP": {
"description": "UDP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_udp"]
},
"lport": {
"description": "Local port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"rhost": {
"description": "Remote host",
"type": "string",
"minLength": 1
},
"rport": {
"description": "Remote port",
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"required": ["type", "lport", "rhost", "rport"],
"additionalProperties": False
},
"Ethernet": {
"description": "Generic Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_generic_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"LinuxEthernet": {
"description": "Linux Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_linux_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"TAP": {
"description": "TAP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_tap"]
},
"tap_device": {
"description": "TAP device name e.g. tap0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "tap_device"],
"additionalProperties": False
},
"UNIX": {
"description": "UNIX Network Input/Output",
"properties": {
"type": {
"enum": ["nio_unix"]
},
"local_file": {
"description": "path to the UNIX socket file (local)",
"type": "string",
"minLength": 1
},
"remote_file": {
"description": "path to the UNIX socket file (remote)",
"type": "string",
"minLength": 1
},
},
"required": ["type", "local_file", "remote_file"],
"additionalProperties": False
},
"VDE": {
"description": "VDE Network Input/Output",
"properties": {
"type": {
"enum": ["nio_vde"]
},
"control_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
"local_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
},
"required": ["type", "control_file", "local_file"],
"additionalProperties": False
},
"NULL": {
"description": "NULL Network Input/Output",
"properties": {
"type": {
"enum": ["nio_null"]
},
},
"required": ["type"],
"additionalProperties": False
},
},
"properties": {
"id": {
"description": "IOU device instance ID",
"type": "integer"
},
"port_id": {
"description": "Unique port identifier for the IOU instance",
"type": "integer"
},
"slot": {
"description": "Slot number",
"type": "integer",
"minimum": 0,
"maximum": 15
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 0,
"maximum": 3
},
"slot": {
"description": "Slot number",
"type": "integer",
"minimum": 0,
"maximum": 15
},
"nio": {
"type": "object",
"description": "Network Input/Output",
"oneOf": [
{"$ref": "#/definitions/UDP"},
{"$ref": "#/definitions/Ethernet"},
{"$ref": "#/definitions/LinuxEthernet"},
{"$ref": "#/definitions/TAP"},
{"$ref": "#/definitions/UNIX"},
{"$ref": "#/definitions/VDE"},
{"$ref": "#/definitions/NULL"},
]
},
},
"required": ["id", "port_id", "slot", "port", "nio"]
}
IOU_DELETE_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to delete a NIO for an IOU instance",
"type": "object",
"properties": {
"id": {
"description": "IOU device instance ID",
"type": "integer"
},
"slot": {
"description": "Slot number",
"type": "integer",
"minimum": 0,
"maximum": 15
},
"port": {
"description": "Port number",
"type": "integer",
"minimum": 0,
"maximum": 3
},
},
"required": ["id", "slot", "port"]
}

@ -23,5 +23,5 @@
# or negative for a release candidate or beta (after the base version # or negative for a release candidate or beta (after the base version
# number has been incremented) # number has been incremented)
__version__ = "1.0a3.dev1" __version__ = "1.0a3.dev2"
__version_info__ = (1, 0, 0, -99) __version_info__ = (1, 0, 0, -99)

@ -1,3 +1,4 @@
tornado tornado
pyzmq pyzmq
netifaces-py3 netifaces-py3
jsonschema

@ -47,6 +47,7 @@ setup(
install_requires=[ install_requires=[
"tornado >= 3.1", "tornado >= 3.1",
"pyzmq", "pyzmq",
"jsonschema"
], ],
entry_points={ entry_points={
"console_scripts": [ "console_scripts": [

Loading…
Cancel
Save