From cb763e0926fc495cfc7ba6550a5f83cbb9756978 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sun, 15 Jun 2014 05:18:33 -0600 Subject: [PATCH] Use Dynamips, IOU and VPCS identifiers to correctly load a topology. --- gns3server/handlers/jsonrpc_websocket.py | 6 +++- gns3server/modules/dynamips/backends/vm.py | 9 +++-- gns3server/modules/dynamips/nodes/c1700.py | 5 +-- gns3server/modules/dynamips/nodes/c2600.py | 5 +-- gns3server/modules/dynamips/nodes/c2691.py | 5 +-- gns3server/modules/dynamips/nodes/c3600.py | 5 +-- gns3server/modules/dynamips/nodes/c3725.py | 5 +-- gns3server/modules/dynamips/nodes/c3745.py | 5 +-- gns3server/modules/dynamips/nodes/c7200.py | 5 +-- gns3server/modules/dynamips/nodes/router.py | 29 +++++++++------ gns3server/modules/dynamips/schemas/vm.py | 4 +++ gns3server/modules/iou/__init__.py | 2 ++ gns3server/modules/iou/iou_device.py | 37 ++++++++++++------- gns3server/modules/iou/schemas.py | 4 +++ gns3server/modules/vpcs/__init__.py | 2 ++ gns3server/modules/vpcs/schemas.py | 4 +++ gns3server/modules/vpcs/vpcs_device.py | 40 ++++++++++++++------- gns3server/version.py | 2 +- 18 files changed, 117 insertions(+), 57 deletions(-) diff --git a/gns3server/handlers/jsonrpc_websocket.py b/gns3server/handlers/jsonrpc_websocket.py index d1db0e14..677ebe2d 100644 --- a/gns3server/handlers/jsonrpc_websocket.py +++ b/gns3server/handlers/jsonrpc_websocket.py @@ -176,7 +176,11 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler): Invoked when the WebSocket is closed. """ - log.info("Websocket client {} disconnected".format(self.session_id)) + try: + log.info("Websocket client {} disconnected".format(self.session_id)) + except RuntimeError: + # to ignore logging exception: RuntimeError: reentrant call inside <_io.BufferedWriter name=''> + pass self.clients.remove(self) # Reset the modules if there are no clients anymore diff --git a/gns3server/modules/dynamips/backends/vm.py b/gns3server/modules/dynamips/backends/vm.py index 56274d9f..c757c7b4 100644 --- a/gns3server/modules/dynamips/backends/vm.py +++ b/gns3server/modules/dynamips/backends/vm.py @@ -132,9 +132,8 @@ class VM(object): image = request["image"] ram = request["ram"] hypervisor = None - chassis = None - if "chassis" in request: - chassis = request["chassis"] + chassis = request.get("chassis") + router_id = request.get("router_id") try: @@ -147,9 +146,9 @@ class VM(object): hypervisor = self._hypervisor_manager.allocate_hypervisor_for_router(image, ram) if chassis: - router = PLATFORMS[platform](hypervisor, name, chassis=chassis) + router = PLATFORMS[platform](hypervisor, name, router_id, chassis=chassis) else: - router = PLATFORMS[platform](hypervisor, name) + router = PLATFORMS[platform](hypervisor, name, router_id) router.ram = ram router.image = image router.sparsemem = self._hypervisor_manager.sparse_memory_support diff --git a/gns3server/modules/dynamips/nodes/c1700.py b/gns3server/modules/dynamips/nodes/c1700.py index 09d75d31..0d59f616 100644 --- a/gns3server/modules/dynamips/nodes/c1700.py +++ b/gns3server/modules/dynamips/nodes/c1700.py @@ -34,13 +34,14 @@ class C1700(Router): :param hypervisor: Dynamips hypervisor instance :param name: name for this router + :param router_id: router instance ID :param chassis: chassis for this router: 1720, 1721, 1750, 1751 or 1760 (default = 1720). 1710 is not supported. """ - def __init__(self, hypervisor, name, chassis="1720"): - Router.__init__(self, hypervisor, name, platform="c1700") + def __init__(self, hypervisor, name, router_id=None, chassis="1720"): + Router.__init__(self, hypervisor, name, router_id, platform="c1700") # Set default values for this platform self._ram = 64 diff --git a/gns3server/modules/dynamips/nodes/c2600.py b/gns3server/modules/dynamips/nodes/c2600.py index ff0fb0c0..155fbf2f 100644 --- a/gns3server/modules/dynamips/nodes/c2600.py +++ b/gns3server/modules/dynamips/nodes/c2600.py @@ -36,6 +36,7 @@ class C2600(Router): :param hypervisor: Dynamips hypervisor instance :param name: name for this router + :param router_id: router instance ID :param chassis: chassis for this router: 2610, 2611, 2620, 2621, 2610XM, 2611XM 2620XM, 2621XM, 2650XM or 2651XM (default = 2610). @@ -54,8 +55,8 @@ class C2600(Router): "2650XM": C2600_MB_1FE, "2651XM": C2600_MB_2FE} - def __init__(self, hypervisor, name, chassis="2610"): - Router.__init__(self, hypervisor, name, platform="c2600") + def __init__(self, hypervisor, name, router_id=None, chassis="2610"): + Router.__init__(self, hypervisor, name, router_id, platform="c2600") # Set default values for this platform self._ram = 64 diff --git a/gns3server/modules/dynamips/nodes/c2691.py b/gns3server/modules/dynamips/nodes/c2691.py index baec82de..339fada9 100644 --- a/gns3server/modules/dynamips/nodes/c2691.py +++ b/gns3server/modules/dynamips/nodes/c2691.py @@ -33,10 +33,11 @@ class C2691(Router): :param hypervisor: Dynamips hypervisor instance :param name: name for this router + :param router_id: router instance ID """ - def __init__(self, hypervisor, name): - Router.__init__(self, hypervisor, name, platform="c2691") + def __init__(self, hypervisor, name, router_id=None): + Router.__init__(self, hypervisor, name, router_id, platform="c2691") # Set default values for this platform self._ram = 128 diff --git a/gns3server/modules/dynamips/nodes/c3600.py b/gns3server/modules/dynamips/nodes/c3600.py index fd9790d4..b0117a16 100644 --- a/gns3server/modules/dynamips/nodes/c3600.py +++ b/gns3server/modules/dynamips/nodes/c3600.py @@ -33,12 +33,13 @@ class C3600(Router): :param hypervisor: Dynamips hypervisor instance :param name: name for this router + :param router_id: router instance ID :param chassis: chassis for this router: 3620, 3640 or 3660 (default = 3640). """ - def __init__(self, hypervisor, name, chassis="3640"): - Router.__init__(self, hypervisor, name, platform="c3600") + def __init__(self, hypervisor, name, router_id=None, chassis="3640"): + Router.__init__(self, hypervisor, name, router_id, platform="c3600") # Set default values for this platform self._ram = 128 diff --git a/gns3server/modules/dynamips/nodes/c3725.py b/gns3server/modules/dynamips/nodes/c3725.py index 455575ce..9317a393 100644 --- a/gns3server/modules/dynamips/nodes/c3725.py +++ b/gns3server/modules/dynamips/nodes/c3725.py @@ -33,10 +33,11 @@ class C3725(Router): :param hypervisor: Dynamips hypervisor instance :param name: name for this router + :param router_id: router instance ID """ - def __init__(self, hypervisor, name): - Router.__init__(self, hypervisor, name, platform="c3725") + def __init__(self, hypervisor, name, router_id=None): + Router.__init__(self, hypervisor, name, router_id, platform="c3725") # Set default values for this platform self._ram = 128 diff --git a/gns3server/modules/dynamips/nodes/c3745.py b/gns3server/modules/dynamips/nodes/c3745.py index 5c914fee..f8392cc3 100644 --- a/gns3server/modules/dynamips/nodes/c3745.py +++ b/gns3server/modules/dynamips/nodes/c3745.py @@ -33,10 +33,11 @@ class C3745(Router): :param hypervisor: Dynamips hypervisor instance :param name: name for this router + :param router_id: router instance ID """ - def __init__(self, hypervisor, name): - Router.__init__(self, hypervisor, name, platform="c3745") + def __init__(self, hypervisor, name, router_id=None): + Router.__init__(self, hypervisor, name, router_id, platform="c3745") # Set default values for this platform self._ram = 128 diff --git a/gns3server/modules/dynamips/nodes/c7200.py b/gns3server/modules/dynamips/nodes/c7200.py index ce63e726..0dd7127b 100644 --- a/gns3server/modules/dynamips/nodes/c7200.py +++ b/gns3server/modules/dynamips/nodes/c7200.py @@ -35,11 +35,12 @@ class C7200(Router): :param hypervisor: Dynamips hypervisor instance :param name: name for this router + :param router_id: router instance ID :param npe: default NPE """ - def __init__(self, hypervisor, name, npe="npe-400"): - Router.__init__(self, hypervisor, name, platform="c7200") + def __init__(self, hypervisor, name, router_id=None, npe="npe-400"): + Router.__init__(self, hypervisor, name, router_id, platform="c7200") # Set default values for this platform self._ram = 256 diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index 525c4e36..174a7136 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -37,6 +37,7 @@ class Router(object): :param hypervisor: Dynamips hypervisor instance :param name: name for this router + :param router_id: router instance ID :param platform: c7200, c3745, c3725, c3600, c2691, c2600 or c1700 :param ghost_flag: used when creating a ghost IOS. """ @@ -49,20 +50,26 @@ class Router(object): 2: "running", 3: "suspended"} - def __init__(self, hypervisor, name, platform="c7200", ghost_flag=False): + def __init__(self, hypervisor, name, router_id=None, platform="c7200", ghost_flag=False): if not ghost_flag: - # find an instance identifier (0 < id <= 4096) - self._id = 0 - for identifier in range(1, 4097): - if identifier not in self._instances: - self._id = identifier - self._instances.append(self._id) - break - - if self._id == 0: - raise DynamipsError("Maximum number of instances reached") + if not router_id: + # find an instance identifier if none is provided (0 < id <= 4096) + self._id = 0 + for identifier in range(1, 4097): + if identifier not in self._instances: + self._id = identifier + self._instances.append(self._id) + break + + if self._id == 0: + raise DynamipsError("Maximum number of instances reached") + else: + if router_id in self._instances: + raise DynamipsError("Router identifier {} is already used by another router".format(router_id)) + self._id = router_id + self._instances.append(self._id) else: log.info("creating a new ghost IOS file") diff --git a/gns3server/modules/dynamips/schemas/vm.py b/gns3server/modules/dynamips/schemas/vm.py index 3a7d9af5..3d4d1078 100644 --- a/gns3server/modules/dynamips/schemas/vm.py +++ b/gns3server/modules/dynamips/schemas/vm.py @@ -25,6 +25,10 @@ VM_CREATE_SCHEMA = { "type": "string", "minLength": 1, }, + "router_id": { + "description": "VM/router instance ID", + "type": "integer" + }, "platform": { "description": "router platform", "type": "string", diff --git a/gns3server/modules/iou/__init__.py b/gns3server/modules/iou/__init__.py index 13a3e252..f579b92c 100644 --- a/gns3server/modules/iou/__init__.py +++ b/gns3server/modules/iou/__init__.py @@ -290,12 +290,14 @@ class IOU(IModule): name = request["name"] iou_path = request["path"] console = request.get("console") + iou_id = request.get("iou_id") try: iou_instance = IOUDevice(name, iou_path, self._working_dir, self._host, + iou_id, console, self._console_start_port_range, self._console_end_port_range) diff --git a/gns3server/modules/iou/iou_device.py b/gns3server/modules/iou/iou_device.py index f465fdfa..96a5d207 100644 --- a/gns3server/modules/iou/iou_device.py +++ b/gns3server/modules/iou/iou_device.py @@ -46,10 +46,11 @@ class IOUDevice(object): """ IOU device implementation. + :param name: name of this IOU device :param path: path to IOU executable :param working_dir: path to a working directory :param host: host/address to bind for console and UDP connections - :param name: name of this IOU device + :param iou_id: IOU instance ID :param console: TCP console port :param console_start_port_range: TCP console port range start :param console_end_port_range: TCP console port range end @@ -63,20 +64,27 @@ class IOUDevice(object): path, working_dir, host="127.0.0.1", + iou_id = None, console=None, console_start_port_range=4001, console_end_port_range=4512): - # find an instance identifier (0 < id <= 512) - self._id = 0 - for identifier in range(1, 513): - if identifier not in self._instances: - self._id = identifier - self._instances.append(self._id) - break - - if self._id == 0: - raise IOUError("Maximum number of IOU instances reached") + if not iou_id: + # find an instance identifier if none is provided (0 < id <= 512) + self._id = 0 + for identifier in range(1, 513): + if identifier not in self._instances: + self._id = identifier + self._instances.append(self._id) + break + + if self._id == 0: + raise IOUError("Maximum number of IOU instances reached") + else: + if iou_id in self._instances: + raise IOUError("IOU identifier {} is already used by another IOU device".format(iou_id)) + self._id = iou_id + self._instances.append(self._id) self._name = name self._path = path @@ -106,8 +114,13 @@ class IOUDevice(object): self._ram = 256 # Megabytes self._l1_keepalives = False # used to overcome the always-up Ethernet interfaces (not supported by all IOSes). + working_dir_path = os.path.join(working_dir, "iou", "device-{}".format(self._id)) + + if iou_id and not os.path.isdir(working_dir_path): + raise IOUError("Working directory {} doesn't exist".format(working_dir_path)) + # create the device own working directory - self.working_dir = os.path.join(working_dir, "iou", "{}".format(self._name)) + self.working_dir = working_dir_path if not self._console: # allocate a console port diff --git a/gns3server/modules/iou/schemas.py b/gns3server/modules/iou/schemas.py index 1d7ed554..1ee41107 100644 --- a/gns3server/modules/iou/schemas.py +++ b/gns3server/modules/iou/schemas.py @@ -26,6 +26,10 @@ IOU_CREATE_SCHEMA = { "type": "string", "minLength": 1, }, + "iou_id": { + "description": "IOU device instance ID", + "type": "integer" + }, "console": { "description": "console TCP port", "minimum": 1, diff --git a/gns3server/modules/vpcs/__init__.py b/gns3server/modules/vpcs/__init__.py index 4a0f1a4b..c7493d4d 100644 --- a/gns3server/modules/vpcs/__init__.py +++ b/gns3server/modules/vpcs/__init__.py @@ -226,6 +226,7 @@ class VPCS(IModule): name = request["name"] console = request.get("console") + vpcs_id = request.get("vpcs_id") try: @@ -236,6 +237,7 @@ class VPCS(IModule): self._vpcs, self._working_dir, self._host, + vpcs_id, console, self._console_start_port_range, self._console_end_port_range) diff --git a/gns3server/modules/vpcs/schemas.py b/gns3server/modules/vpcs/schemas.py index 7258bda2..d7ca8b87 100644 --- a/gns3server/modules/vpcs/schemas.py +++ b/gns3server/modules/vpcs/schemas.py @@ -26,6 +26,10 @@ VPCS_CREATE_SCHEMA = { "type": "string", "minLength": 1, }, + "vpcs_id": { + "description": "VPCS device instance ID", + "type": "integer" + }, "console": { "description": "console TCP port", "minimum": 1, diff --git a/gns3server/modules/vpcs/vpcs_device.py b/gns3server/modules/vpcs/vpcs_device.py index 09152328..cb3c4f06 100644 --- a/gns3server/modules/vpcs/vpcs_device.py +++ b/gns3server/modules/vpcs/vpcs_device.py @@ -40,10 +40,11 @@ class VPCSDevice(object): """ VPCS device implementation. + :param name: name of this VPCS device :param path: path to VPCS executable :param working_dir: path to a working directory :param host: host/address to bind for console and UDP connections - :param name: name of this VPCS device + :param vpcs_id: VPCS instance ID :param console: TCP console port :param console_start_port_range: TCP console port range start :param console_end_port_range: TCP console port range end @@ -57,22 +58,30 @@ class VPCSDevice(object): path, working_dir, host="127.0.0.1", + vpcs_id=None, console=None, console_start_port_range=4512, console_end_port_range=5000): - # find an instance identifier (1 <= id <= 255) - # This 255 limit is due to a restriction on the number of possible - # MAC addresses given in VPCS using the -m option - self._id = 0 - for identifier in range(1, 256): - if identifier not in self._instances: - self._id = identifier - self._instances.append(self._id) - break - if self._id == 0: - raise VPCSError("Maximum number of VPCS instances reached") + if not vpcs_id: + # find an instance identifier is none is provided (1 <= id <= 255) + # This 255 limit is due to a restriction on the number of possible + # MAC addresses given in VPCS using the -m option + self._id = 0 + for identifier in range(1, 256): + if identifier not in self._instances: + self._id = identifier + self._instances.append(self._id) + break + + if self._id == 0: + raise VPCSError("Maximum number of VPCS instances reached") + else: + if vpcs_id in self._instances: + raise VPCSError("VPCS identifier {} is already used by another VPCS device".format(vpcs_id)) + self._id = vpcs_id + self._instances.append(self._id) self._name = name self._path = path @@ -91,8 +100,13 @@ class VPCSDevice(object): self._script_file = "" self._ethernet_adapter = EthernetAdapter() # one adapter with 1 Ethernet interface + working_dir_path = os.path.join(working_dir, "vpcs", "pc-{}".format(self._id)) + + if vpcs_id and not os.path.isdir(working_dir_path): + raise VPCSError("Working directory {} doesn't exist".format(working_dir_path)) + # create the device own working directory - self.working_dir = os.path.join(working_dir, "vpcs", "{}".format(name)) + self.working_dir = working_dir_path if not self._console: # allocate a console port diff --git a/gns3server/version.py b/gns3server/version.py index a40a2cfa..beca4a33 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,5 +23,5 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "1.0a7.dev1" +__version__ = "1.0a7.dev2" __version_info__ = (1, 0, 0, -99)