From 9adfb1820de937d393902f81f537e42726a9e3df Mon Sep 17 00:00:00 2001 From: grossmj Date: Fri, 13 Apr 2018 14:17:18 +0800 Subject: [PATCH 01/12] Remove 'include INSTALL' from MANIFEST. --- MANIFEST.in | 1 - 1 file changed, 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 61bdd940..38cadc48 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,5 @@ include README.rst include AUTHORS -include INSTALL include LICENSE include MANIFEST.in include tox.ini From 2de182eff41f525ae6e75f5c0a26d3b691cbd3a6 Mon Sep 17 00:00:00 2001 From: grossmj Date: Fri, 13 Apr 2018 16:54:57 +0800 Subject: [PATCH 02/12] Grid size support for projects. --- gns3server/controller/project.py | 20 +++++++++++++++++++- gns3server/controller/topology.py | 1 + gns3server/schemas/project.py | 12 ++++++++++++ gns3server/schemas/topology.py | 4 ++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index 8a459c84..aa6aed06 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -68,7 +68,7 @@ class Project: def __init__(self, name=None, project_id=None, path=None, controller=None, status="opened", filename=None, auto_start=False, auto_open=False, auto_close=True, scene_height=1000, scene_width=2000, zoom=100, show_layers=False, snap_to_grid=False, show_grid=False, - show_interface_labels=False): + grid_size=0, show_interface_labels=False): self._controller = controller assert name is not None @@ -83,6 +83,7 @@ class Project: self._show_layers = show_layers self._snap_to_grid = snap_to_grid self._show_grid = show_grid + self._grid_size = grid_size self._show_interface_labels = show_interface_labels self._loading = False @@ -235,6 +236,21 @@ class Project: """ self._show_grid = show_grid + @property + def grid_size(self): + """ + Grid size + :return: integer + """ + return self._grid_size + + @grid_size.setter + def grid_size(self, grid_size): + """ + Setter for grid size + """ + self._grid_size = grid_size + @property def show_interface_labels(self): """ @@ -760,6 +776,7 @@ class Project: "show_layers", "snap_to_grid", "show_grid", + "grid_size", "show_interface_labels" ] @@ -999,6 +1016,7 @@ class Project: "show_layers": self._show_layers, "snap_to_grid": self._snap_to_grid, "show_grid": self._show_grid, + "grid_size": self._grid_size, "show_interface_labels": self._show_interface_labels } diff --git a/gns3server/controller/topology.py b/gns3server/controller/topology.py index d88db985..efee8377 100644 --- a/gns3server/controller/topology.py +++ b/gns3server/controller/topology.py @@ -83,6 +83,7 @@ def project_to_topology(project): "show_layers": project.show_layers, "snap_to_grid": project.snap_to_grid, "show_grid": project.show_grid, + "grid_size": project.grid_size, "show_interface_labels": project.show_interface_labels, "topology": { "nodes": [], diff --git a/gns3server/schemas/project.py b/gns3server/schemas/project.py index eb008389..242f5e5b 100644 --- a/gns3server/schemas/project.py +++ b/gns3server/schemas/project.py @@ -66,6 +66,10 @@ PROJECT_CREATE_SCHEMA = { "type": "boolean", "description": "Show the grid on the drawing area" }, + "grid_size": { + "type": "integer", + "description": "Grid size for the drawing area" + }, "show_interface_labels": { "type": "boolean", "description": "Show interface labels on the drawing area" @@ -125,6 +129,10 @@ PROJECT_UPDATE_SCHEMA = { "type": "boolean", "description": "Show the grid on the drawing area" }, + "grid_size": { + "type": "integer", + "description": "Grid size for the drawing area" + }, "show_interface_labels": { "type": "boolean", "description": "Show interface labels on the drawing area" @@ -200,6 +208,10 @@ PROJECT_OBJECT_SCHEMA = { "type": "boolean", "description": "Show the grid on the drawing area" }, + "grid_size": { + "type": "integer", + "description": "Grid size for the drawing area" + }, "show_interface_labels": { "type": "boolean", "description": "Show interface labels on the drawing area" diff --git a/gns3server/schemas/topology.py b/gns3server/schemas/topology.py index bf9fc1cf..faadf81b 100644 --- a/gns3server/schemas/topology.py +++ b/gns3server/schemas/topology.py @@ -89,6 +89,10 @@ TOPOLOGY_SCHEMA = { "type": "boolean", "description": "Show the grid on the drawing area" }, + "grid_size": { + "type": "integer", + "description": "Grid size for the drawing area" + }, "show_interface_labels": { "type": "boolean", "description": "Show interface labels on the drawing area" From 801547983a3f5119404ad97c2bdcc1ba52536458 Mon Sep 17 00:00:00 2001 From: grossmj Date: Fri, 13 Apr 2018 17:04:19 +0800 Subject: [PATCH 03/12] Fix tests. --- tests/controller/test_project.py | 3 ++- tests/controller/test_topology.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/controller/test_project.py b/tests/controller/test_project.py index deb61b16..77f8e799 100644 --- a/tests/controller/test_project.py +++ b/tests/controller/test_project.py @@ -75,7 +75,8 @@ def test_json(tmpdir): "show_grid": False, "show_interface_labels": False, "show_layers": False, - "snap_to_grid": False + "snap_to_grid": False, + "grid_size": 0, } diff --git a/tests/controller/test_topology.py b/tests/controller/test_topology.py index 01dbf245..b5d4b12f 100644 --- a/tests/controller/test_topology.py +++ b/tests/controller/test_topology.py @@ -45,6 +45,7 @@ def test_project_to_topology_empty(tmpdir): "show_interface_labels": False, "show_layers": False, "snap_to_grid": False, + "grid_size": 0, "topology": { "nodes": [], "links": [], From 025441f027195b0a85426294c1926f45e980d613 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 16 Apr 2018 15:03:22 +0800 Subject: [PATCH 04/12] Add default destination setting for traceng + some checks. --- gns3server/compute/traceng/traceng_vm.py | 33 ++++++++++++++++++- gns3server/controller/project.py | 5 --- .../handlers/api/compute/traceng_handler.py | 6 ++-- gns3server/schemas/traceng.py | 15 +++++++-- 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/gns3server/compute/traceng/traceng_vm.py b/gns3server/compute/traceng/traceng_vm.py index cdd97741..6539b804 100644 --- a/gns3server/compute/traceng/traceng_vm.py +++ b/gns3server/compute/traceng/traceng_vm.py @@ -59,6 +59,7 @@ class TraceNGVM(BaseNode): self._process = None self._started = False self._ip_address = None + self._default_destination = None self._destination = None self._local_udp_tunnel = None self._ethernet_adapter = EthernetAdapter() # one adapter with 1 Ethernet interface @@ -115,6 +116,7 @@ class TraceNGVM(BaseNode): return {"name": self.name, "ip_address": self.ip_address, + "default_destination": self._default_destination, "node_id": self.id, "node_directory": self.working_path, "status": self.status, @@ -167,6 +169,30 @@ class TraceNGVM(BaseNode): id=self.id, ip_address=ip_address)) + @property + def default_destination(self): + """ + Returns the default destination IP/host for this node. + + :returns: destination IP/host + """ + + return self._default_destination + + @default_destination.setter + def default_destination(self, destination): + """ + Sets the destination IP/host for this node. + + :param destination: destination IP/host + """ + + self._default_destination = destination + log.info("{module}: {name} [{id}] set default destination to {destination}".format(module=self.manager.module_name, + name=self.name, + id=self.id, + destination=destination)) + @asyncio.coroutine def start(self, destination=None): """ @@ -400,10 +426,15 @@ class TraceNGVM(BaseNode): (to be passed to subprocess.Popen()) """ + if not destination: + # use the default destination if no specific destination provided + destination = self.default_destination if not destination: raise TraceNGError("Please provide a host or IP address to trace") - if not self._ip_address: + if not self.ip_address: raise TraceNGError("Please configure an IP address for this TraceNG node") + if self.ip_address == destination: + raise TraceNGError("Destination cannot be the same as the IP address") self._destination = destination command = [self._traceng_path()] diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index aa6aed06..24306cb6 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -921,12 +921,7 @@ class Project: Start all nodes """ pool = Pool(concurrency=3) - emit_warning = True for node in self.nodes.values(): - if node.node_type == "traceng" and emit_warning: - self.controller.notification.emit("log.warning", {"message": "TraceNG nodes must be started one by one"}) - emit_warning = False - continue pool.append(node.start) yield from pool.join() diff --git a/gns3server/handlers/api/compute/traceng_handler.py b/gns3server/handlers/api/compute/traceng_handler.py index 188cde5f..fc5d21c8 100644 --- a/gns3server/handlers/api/compute/traceng_handler.py +++ b/gns3server/handlers/api/compute/traceng_handler.py @@ -55,7 +55,8 @@ class TraceNGHandler: request.match_info["project_id"], request.json.get("node_id"), console=request.json.get("console")) - vm.ip_address = request.json.get("ip_address", "") # FIXME, required IP address to create node? + vm.ip_address = request.json.get("ip_address", "") + vm.default_destination = request.json.get("default_destination", "") response.set_status(201) response.json(vm) @@ -99,6 +100,7 @@ class TraceNGHandler: vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) vm.name = request.json.get("name", vm.name) vm.ip_address = request.json.get("ip_address", vm.ip_address) + vm.default_destination = request.json.get("default_destination", vm.default_destination) vm.updated() response.json(vm) @@ -157,7 +159,7 @@ class TraceNGHandler: traceng_manager = TraceNG.instance() vm = traceng_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) - yield from vm.start(request.json["destination"]) + yield from vm.start(request.get("destination")) response.json(vm) @Route.post( diff --git a/gns3server/schemas/traceng.py b/gns3server/schemas/traceng.py index 6c0f63cc..d95fd042 100644 --- a/gns3server/schemas/traceng.py +++ b/gns3server/schemas/traceng.py @@ -48,6 +48,10 @@ TRACENG_CREATE_SCHEMA = { "ip_address": { "description": "Source IP address for tracing", "type": ["string"] + }, + "default_destination": { + "description": "Default destination IP address or hostname for tracing", + "type": ["string"] } }, "additionalProperties": False, @@ -77,6 +81,10 @@ TRACENG_UPDATE_SCHEMA = { "ip_address": { "description": "Source IP address for tracing", "type": ["string"] + }, + "default_destination": { + "description": "Default destination IP address or hostname for tracing", + "type": ["string"] } }, "additionalProperties": False, @@ -92,7 +100,6 @@ TRACENG_START_SCHEMA = { "type": ["string"] } }, - "required": ["destination"], } TRACENG_OBJECT_SCHEMA = { @@ -144,8 +151,12 @@ TRACENG_OBJECT_SCHEMA = { "ip_address": { "description": "Source IP address for tracing", "type": ["string"] + }, + "default_destination": { + "description": "Default destination IP address or hostname for tracing", + "type": ["string"] } }, "additionalProperties": False, - "required": ["name", "node_id", "status", "console", "console_type", "project_id", "command_line", "ip_address"] + "required": ["name", "node_id", "status", "console", "console_type", "project_id", "command_line", "ip_address", "default_destination"] } From a12c5a95b0c3c56c9eca27a18e4c5256b4b95b38 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 16 Apr 2018 15:30:06 +0800 Subject: [PATCH 05/12] Catch exceptions when using AsyncioTelnetServer. Fixes #1321. --- gns3server/compute/base_node.py | 1 + gns3server/compute/docker/docker_vm.py | 10 ++++++++-- gns3server/compute/dynamips/nodes/ethernet_switch.py | 6 ++++-- gns3server/compute/iou/iou_vm.py | 6 +++++- gns3server/compute/virtualbox/virtualbox_vm.py | 5 ++++- gns3server/compute/vmware/vmware_vm.py | 5 ++++- 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/gns3server/compute/base_node.py b/gns3server/compute/base_node.py index c2a4e68e..c536a46e 100644 --- a/gns3server/compute/base_node.py +++ b/gns3server/compute/base_node.py @@ -346,6 +346,7 @@ class BaseNode: remaining_trial -= 1 yield from AsyncioTelnetServer.write_client_intro(writer, echo=True) server = AsyncioTelnetServer(reader=reader, writer=writer, binary=True, echo=True) + # warning: this will raise OSError exception if there is a problem... self._wrapper_telnet_server = yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console) @property diff --git a/gns3server/compute/docker/docker_vm.py b/gns3server/compute/docker/docker_vm.py index 3d291550..d9f9f12d 100644 --- a/gns3server/compute/docker/docker_vm.py +++ b/gns3server/compute/docker/docker_vm.py @@ -412,7 +412,10 @@ class DockerVM(BaseNode): stderr=asyncio.subprocess.STDOUT, stdin=asyncio.subprocess.PIPE) server = AsyncioTelnetServer(reader=process.stdout, writer=process.stdin, binary=True, echo=True) - self._telnet_servers.append((yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.aux))) + try: + self._telnet_servers.append((yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.aux))) + except OSError as e: + raise DockerError("Could not start Telnet server on socket {}:{}: {}".format(self._manager.port_manager.console_host, self.aux, e)) log.debug("Docker container '%s' started listen for auxilary telnet on %d", self.name, self.aux) @asyncio.coroutine @@ -508,7 +511,10 @@ class DockerVM(BaseNode): input_stream = InputStream() telnet = AsyncioTelnetServer(reader=output_stream, writer=input_stream, echo=True) - self._telnet_servers.append((yield from asyncio.start_server(telnet.run, self._manager.port_manager.console_host, self.console))) + try: + self._telnet_servers.append((yield from asyncio.start_server(telnet.run, self._manager.port_manager.console_host, self.console))) + except OSError as e: + raise DockerError("Could not start Telnet server on socket {}:{}: {}".format(self._manager.port_manager.console_host, self.console, e)) self._console_websocket = yield from self.manager.websocket_query("containers/{}/attach/ws?stream=1&stdin=1&stdout=1&stderr=1".format(self._cid)) input_stream.ws = self._console_websocket diff --git a/gns3server/compute/dynamips/nodes/ethernet_switch.py b/gns3server/compute/dynamips/nodes/ethernet_switch.py index 841a47c9..594b3cb5 100644 --- a/gns3server/compute/dynamips/nodes/ethernet_switch.py +++ b/gns3server/compute/dynamips/nodes/ethernet_switch.py @@ -167,8 +167,10 @@ class EthernetSwitch(Device): self._telnet_shell = EthernetSwitchConsole(self) self._telnet_shell.prompt = self._name + '> ' self._telnet = create_telnet_shell(self._telnet_shell) - self._telnet_server = (yield from asyncio.start_server(self._telnet.run, self._manager.port_manager.console_host, self.console)) - + try: + self._telnet_server = (yield from asyncio.start_server(self._telnet.run, self._manager.port_manager.console_host, self.console)) + except OSError as e: + self.project.emit("log.warning", {"message": "Could not start Telnet server on socket {}:{}: {}".format(self._manager.port_manager.console_host, self.console, e)}) self._hypervisor.devices.append(self) @asyncio.coroutine diff --git a/gns3server/compute/iou/iou_vm.py b/gns3server/compute/iou/iou_vm.py index c863d22e..0f2cb636 100644 --- a/gns3server/compute/iou/iou_vm.py +++ b/gns3server/compute/iou/iou_vm.py @@ -541,7 +541,11 @@ class IOUVM(BaseNode): raise IOUError("Could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout)) server = AsyncioTelnetServer(reader=self._iou_process.stdout, writer=self._iou_process.stdin, binary=True, echo=True) - self._telnet_server = yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console) + try: + self._telnet_server = yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console) + except OSError as e: + yield from self.stop() + raise IOUError("Could not start Telnet server on socket {}:{}: {}".format(self._manager.port_manager.console_host, self.console, e)) # configure networking support yield from self._networking() diff --git a/gns3server/compute/virtualbox/virtualbox_vm.py b/gns3server/compute/virtualbox/virtualbox_vm.py index 1e20ebaf..2f878ffe 100644 --- a/gns3server/compute/virtualbox/virtualbox_vm.py +++ b/gns3server/compute/virtualbox/virtualbox_vm.py @@ -942,7 +942,10 @@ class VirtualBoxVM(BaseNode): writer=self._remote_pipe, binary=True, echo=True) - self._telnet_server = yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console) + try: + self._telnet_server = yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console) + except OSError as e: + self.project.emit("log.warning", {"message": "Could not start Telnet server on socket {}:{}: {}".format(self._manager.port_manager.console_host, self.console, e)}) @asyncio.coroutine def _stop_remote_console(self): diff --git a/gns3server/compute/vmware/vmware_vm.py b/gns3server/compute/vmware/vmware_vm.py index 3e2e58df..b96af8e3 100644 --- a/gns3server/compute/vmware/vmware_vm.py +++ b/gns3server/compute/vmware/vmware_vm.py @@ -848,7 +848,10 @@ class VMwareVM(BaseNode): writer=self._remote_pipe, binary=True, echo=True) - self._telnet_server = yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console) + try: + self._telnet_server = yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console) + except OSError as e: + self.project.emit("log.warning", {"message": "Could not start Telnet server on socket {}:{}: {}".format(self._manager.port_manager.console_host, self.console, e)}) @asyncio.coroutine def _stop_remote_console(self): From 5c4f6dd3dc6704c14236880a0250a1ac447cb9ff Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 16 Apr 2018 15:45:43 +0800 Subject: [PATCH 06/12] Do not fail a Dynamips project conversion if a file being used. --- gns3server/compute/dynamips/nodes/router.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gns3server/compute/dynamips/nodes/router.py b/gns3server/compute/dynamips/nodes/router.py index a05e61aa..ec1a0f5c 100644 --- a/gns3server/compute/dynamips/nodes/router.py +++ b/gns3server/compute/dynamips/nodes/router.py @@ -131,14 +131,16 @@ class Router(BaseNode): try: shutil.move(path, dst) except OSError as e: - raise DynamipsError("Can't move {}: {}".format(path, str(e))) + log.error("Can't move {}: {}".format(path, str(e))) + continue for path in glob.glob(os.path.join(glob.escape(dynamips_dir), "*_i{}_*".format(dynamips_id))): dst = os.path.join(self._working_directory, os.path.basename(path)) if not os.path.exists(dst): try: shutil.move(path, dst) except OSError as e: - raise DynamipsError("Can't move {}: {}".format(path, str(e))) + log.error("Can't move {}: {}".format(path, str(e))) + continue def __json__(self): From dd9c18b9f8144d73522b0845b03cc0d63cb9bd7b Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 16 Apr 2018 16:36:36 +0800 Subject: [PATCH 07/12] Use SO_REUSEADDR before calling bind() where missing. Fixes #1289. --- gns3server/compute/base_node.py | 2 +- gns3server/compute/qemu/qemu_vm.py | 1 + gns3server/controller/gns3vm/virtualbox_gns3_vm.py | 1 + gns3server/ubridge/hypervisor.py | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gns3server/compute/base_node.py b/gns3server/compute/base_node.py index c536a46e..ec1d8021 100644 --- a/gns3server/compute/base_node.py +++ b/gns3server/compute/base_node.py @@ -514,7 +514,7 @@ class BaseNode: try: yield from self._ubridge_hypervisor.send(command) except UbridgeError as e: - raise UbridgeError("{}: {}".format(e, self._ubridge_hypervisor.read_stdout())) + raise UbridgeError("Error while sending command '{}': {}: {}".format(command, e, self._ubridge_hypervisor.read_stdout())) @locked_coroutine def _start_ubridge(self): diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index 92a43020..7aeaf446 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -894,6 +894,7 @@ class QemuVM(BaseNode): af, socktype, proto, _, sa = res # let the OS find an unused port for the Qemu monitor with socket.socket(af, socktype, proto) as sock: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(sa) self._monitor = sock.getsockname()[1] except OSError as e: diff --git a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py index cad08b71..f491e32f 100644 --- a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py +++ b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py @@ -191,6 +191,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM): try: # get a random port on localhost with socket.socket() as s: + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((ip_address, 0)) api_port = s.getsockname()[1] except OSError as e: diff --git a/gns3server/ubridge/hypervisor.py b/gns3server/ubridge/hypervisor.py index 660c930a..ed618b06 100644 --- a/gns3server/ubridge/hypervisor.py +++ b/gns3server/ubridge/hypervisor.py @@ -62,6 +62,7 @@ class Hypervisor(UBridgeHypervisor): af, socktype, proto, _, sa = res # let the OS find an unused port for the uBridge hypervisor with socket.socket(af, socktype, proto) as sock: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(sa) port = sock.getsockname()[1] break From 1fea086f131bb8b069517a2a00a4675d57e7597c Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 17 Apr 2018 11:47:25 +0800 Subject: [PATCH 08/12] Do not use VMnet0 when allocating VMnet adapters. --- gns3server/compute/vmware/__init__.py | 8 ++++---- gns3server/compute/vmware/vmware_vm.py | 21 +++++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/gns3server/compute/vmware/__init__.py b/gns3server/compute/vmware/__init__.py index 73f258f9..cda42c54 100644 --- a/gns3server/compute/vmware/__init__.py +++ b/gns3server/compute/vmware/__init__.py @@ -253,7 +253,7 @@ class VMware(BaseManager): if winreg.QueryInfoKey(hkeyvmnet)[1]: # the vmnet has not been configure if the key has no values vmnet = vmnet.replace("vm", "VM") - if vmnet not in ("VMnet1", "VMnet8"): + if vmnet not in ("VMnet0", "VMnet1", "VMnet8"): vmnet_interfaces.append(vmnet) winreg.CloseKey(hkeyvmnet) winreg.CloseKey(hkey) @@ -278,7 +278,7 @@ class VMware(BaseManager): match = re.search("VNET_([0-9]+)_VIRTUAL_ADAPTER", line) if match: vmnet = "vmnet{}".format(match.group(1)) - if vmnet not in ("vmnet1", "vmnet8"): + if vmnet not in ("vmnet0", "vmnet1", "vmnet8"): vmnet_interfaces.append(vmnet) except OSError as e: raise VMwareError("Cannot open {}: {}".format(vmware_networking_file, e)) @@ -297,11 +297,11 @@ class VMware(BaseManager): match = re.search("(VMnet[0-9]+)", windows_name) if match: vmnet = match.group(1) - if vmnet not in ("VMnet1", "VMnet8"): + if vmnet not in ("VMnet0", "VMnet1", "VMnet8"): vmnet_interfaces.append(vmnet) elif interface["name"].startswith("vmnet"): vmnet = interface["name"] - if vmnet not in ("vmnet1", "vmnet8"): + if vmnet not in ("vmnet0", "vmnet1", "vmnet8"): vmnet_interfaces.append(interface["name"]) return vmnet_interfaces diff --git a/gns3server/compute/vmware/vmware_vm.py b/gns3server/compute/vmware/vmware_vm.py index b96af8e3..e048d1c8 100644 --- a/gns3server/compute/vmware/vmware_vm.py +++ b/gns3server/compute/vmware/vmware_vm.py @@ -24,7 +24,6 @@ import os import asyncio import tempfile -from gns3server.utils.interfaces import interfaces from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer from gns3server.utils.asyncio.serial import asyncio_open_serial from gns3server.utils.asyncio import locked_coroutine @@ -277,6 +276,7 @@ class VMwareVM(BaseNode): continue self._vmx_pairs["ethernet{}.connectiontype".format(adapter_number)] = "custom" + # make sure we have a vmnet per adapter if we use uBridge allocate_vmnet = False @@ -285,7 +285,7 @@ class VMwareVM(BaseNode): if vnet in self._vmx_pairs: vmnet = os.path.basename(self._vmx_pairs[vnet]) if self.manager.is_managed_vmnet(vmnet) or vmnet in ("vmnet0", "vmnet1", "vmnet8"): - # vmnet already managed, try to allocate a new one + # vmnet already managed or a special vmnet, try to allocate a new one allocate_vmnet = True else: # otherwise allocate a new one @@ -299,7 +299,7 @@ class VMwareVM(BaseNode): self._vmnets.clear() raise - # mark the vmnet managed by us + # mark the vmnet as managed by us if vmnet not in self._vmnets: self._vmnets.append(vmnet) self._vmx_pairs["ethernet{}.vnet".format(adapter_number)] = vmnet @@ -739,17 +739,18 @@ class VMwareVM(BaseNode): if self._get_vmx_setting("ethernet{}.present".format(adapter_number), "TRUE"): # check for the connection type connection_type = "ethernet{}.connectiontype".format(adapter_number) - if connection_type in self._vmx_pairs and self._vmx_pairs[connection_type] in ("nat", "bridged", "hostonly"): - if not self._use_any_adapter: - raise VMwareError("Attachment '{attachment}' is already configured on network adapter {adapter_number}. " - "Please remove it or allow VMware VM '{name}' to use any adapter.".format(attachment=self._vmx_pairs[connection_type], - adapter_number=adapter_number, - name=self.name)) - elif (yield from self.is_running()): + if not self._use_any_adapter and connection_type in self._vmx_pairs and self._vmx_pairs[connection_type] in ("nat", "bridged", "hostonly"): + if (yield from self.is_running()): raise VMwareError("Attachment '{attachment}' is configured on network adapter {adapter_number}. " "Please stop VMware VM '{name}' to link to this adapter and allow GNS3 to change the attachment type.".format(attachment=self._vmx_pairs[connection_type], adapter_number=adapter_number, name=self.name)) + else: + raise VMwareError("Attachment '{attachment}' is already configured on network adapter {adapter_number}. " + "Please remove it or allow VMware VM '{name}' to use any adapter.".format(attachment=self._vmx_pairs[connection_type], + adapter_number=adapter_number, + name=self.name)) + adapter.add_nio(0, nio) if self._started and self._ubridge_hypervisor: From 5690d350bd78f1b7bad3599ea757f1c996836542 Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 17 Apr 2018 12:58:37 +0800 Subject: [PATCH 09/12] Update appliance files. --- gns3server/appliances/cisco-7200.gns3a | 4 +- gns3server/appliances/cisco-nxosv9k.gns3a | 14 ++++ .../appliances/citrix-netscaler-vpx.gns3a | 13 +++ gns3server/appliances/juniper-vsrx.gns3a | 1 + gns3server/appliances/mikrotik-chr.gns3a | 30 +++++++ gns3server/appliances/pan-vm-fw.gns3a | 84 ++++++++++++++----- gns3server/appliances/vyos.gns3a | 7 ++ 7 files changed, 128 insertions(+), 25 deletions(-) diff --git a/gns3server/appliances/cisco-7200.gns3a b/gns3server/appliances/cisco-7200.gns3a index 538656bd..d3db50e1 100644 --- a/gns3server/appliances/cisco-7200.gns3a +++ b/gns3server/appliances/cisco-7200.gns3a @@ -22,14 +22,14 @@ "images": [ { "filename": "c7200-adventerprisek9-mz.124-24.T5.image", - "version": "124-25.T5", + "version": "124-24.T5", "md5sum": "6b89d0d804e1f2bb5b8bda66b5692047", "filesize": 102345240 } ], "versions": [ { - "name": "124-25.T5", + "name": "124-24.T5", "idlepc": "0x606df838", "images": { "image": "c7200-adventerprisek9-mz.124-24.T5.image" diff --git a/gns3server/appliances/cisco-nxosv9k.gns3a b/gns3server/appliances/cisco-nxosv9k.gns3a index 122f6534..653f4920 100644 --- a/gns3server/appliances/cisco-nxosv9k.gns3a +++ b/gns3server/appliances/cisco-nxosv9k.gns3a @@ -25,6 +25,13 @@ "kvm": "require" }, "images": [ + { + "filename": "nxosv-final.7.0.3.I7.3.qcow2", + "version": "7.0.3.I7.3", + "md5sum": "9d7a20367bf681a239f14097bbce470a", + "filesize": 983629824, + "download_url": "https://software.cisco.com/download/" + }, { "filename": "nxosv-final.7.0.3.I7.2.qcow2", "version": "7.0.3.I7.2", @@ -71,6 +78,13 @@ } ], "versions": [ + { + "name": "7.0.3.I7.3", + "images": { + "bios_image": "OVMF-20160813.fd", + "hda_disk_image": "nxosv-final.7.0.3.I7.3.qcow2" + } + }, { "name": "7.0.3.I7.2", "images": { diff --git a/gns3server/appliances/citrix-netscaler-vpx.gns3a b/gns3server/appliances/citrix-netscaler-vpx.gns3a index 8c62df07..0fcd184a 100644 --- a/gns3server/appliances/citrix-netscaler-vpx.gns3a +++ b/gns3server/appliances/citrix-netscaler-vpx.gns3a @@ -26,6 +26,13 @@ "options": "-smp 2 -cpu host" }, "images": [ + { + "filename": "NSVPX-KVM-12.0-56.20_nc_32.qcow2", + "version": "12.0-56.20", + "md5sum": "0ea1c23e3b8eb8451037d46ee472cfa6", + "filesize": 739704832, + "download_url": "https://www.citrix.com/lp/try/netscaler-vpx-express.html" + }, { "filename": "NSVPX-KVM-11.1-47.14_nc.raw", "version": "11.1-47.14 F", @@ -42,6 +49,12 @@ } ], "versions": [ + { + "name": "12.0-56.20", + "images": { + "hda_disk_image": "NSVPX-KVM-12.0-56.20_nc_32.qcow2" + } + }, { "name": "11.1-47.14 F", "images": { diff --git a/gns3server/appliances/juniper-vsrx.gns3a b/gns3server/appliances/juniper-vsrx.gns3a index 002b9bd9..dfe2cd06 100644 --- a/gns3server/appliances/juniper-vsrx.gns3a +++ b/gns3server/appliances/juniper-vsrx.gns3a @@ -12,6 +12,7 @@ "maintainer": "GNS3 Team", "maintainer_email": "developers@gns3.net", "usage": "Initial username is root, no password.", + "first_port_name": "fxp0", "port_name_format": "ge-0/0/{0}", "qemu": { "adapter_type": "e1000", diff --git a/gns3server/appliances/mikrotik-chr.gns3a b/gns3server/appliances/mikrotik-chr.gns3a index 559b6bd0..c57d80e5 100644 --- a/gns3server/appliances/mikrotik-chr.gns3a +++ b/gns3server/appliances/mikrotik-chr.gns3a @@ -26,6 +26,24 @@ "options": "-nographic" }, "images": [ + { + "filename": "chr-6.41.4.img", + "version": "6.41.4", + "md5sum": "63b555b2b7f0d78b79edb92f7e7d2ed7", + "filesize": 134217728, + "download_url": "http://www.mikrotik.com/download", + "direct_download_url": "https://download2.mikrotik.com/routeros/6.41.4/chr-6.41.4.img.zip", + "compression": "zip" + }, + { + "filename": "chr-6.40.7.img", + "version": "6.40.7", + "md5sum": "424b897d631c4cac4324ca310e81b494", + "filesize": 134217728, + "download_url": "http://www.mikrotik.com/download", + "direct_download_url": "https://download2.mikrotik.com/routeros/6.40.7/chr-6.40.7.img.zip", + "compression": "zip" + }, { "filename": "chr-6.40.5.img", "version": "6.40.5", @@ -235,6 +253,18 @@ } ], "versions": [ + { + "name": "6.41.4", + "images": { + "hda_disk_image": "chr-6.41.4.img" + } + }, + { + "name": "6.40.7", + "images": { + "hda_disk_image": "chr-6.40.7.img" + } + }, { "name": "6.40.5", "images": { diff --git a/gns3server/appliances/pan-vm-fw.gns3a b/gns3server/appliances/pan-vm-fw.gns3a index 9a196132..dc6fd6df 100644 --- a/gns3server/appliances/pan-vm-fw.gns3a +++ b/gns3server/appliances/pan-vm-fw.gns3a @@ -27,17 +27,31 @@ }, "images": [ { - "filename": "PA-VM-ESX-6.1.0-disk1.vmdk", - "version": "6.1.0 (ESX)", - "md5sum": "64b1e81cd54008318235832ea6d71424", - "filesize": 2959736832, + "filename": "PA-VM-ESX-8.1.0-disk1.vmdk", + "version": "8.1.0", + "md5sum": "49af8e8225c2e90414bde0be15eaf421", + "filesize": 2281454080, "download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/" }, { - "filename": "PA-VM-KVM-7.1.0.qcow2", - "version": "7.1.0", - "md5sum": "da300253709740068927408239c2e321", - "filesize": 1858797568, + "filename": "PA-VM-KVM-8.1.0.qcow2", + "version": "8.1.0", + "md5sum": "459558515b965b2e43fde2842abbae66", + "filesize": 2260467712, + "download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/" + }, + { + "filename": "PA-VM-ESX-8.0.0-disk1.vmdk", + "version": "8.0.0", + "md5sum": "a505fb1dbcc855ecf98630fd5d329f9a", + "filesize": 2002713088, + "download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/" + }, + { + "filename": "PA-VM-KVM-8.0.0.qcow2", + "version": "8.0.0", + "md5sum": "b6a1ddc8552aff87f05f9c0d4cb54dc3", + "filesize": 1987444736, "download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/" }, { @@ -48,31 +62,37 @@ "download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/" }, { - "filename": "PA-VM-KVM-8.0.0.qcow2", - "version": "8.0.0", - "md5sum": "b6a1ddc8552aff87f05f9c0d4cb54dc3", - "filesize": 1987444736, + "filename": "PA-VM-KVM-7.1.0.qcow2", + "version": "7.1.0", + "md5sum": "da300253709740068927408239c2e321", + "filesize": 1858797568, "download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/" - } - + }, + { + "filename": "PA-VM-ESX-6.1.0-disk1.vmdk", + "version": "6.1.0 (ESX)", + "md5sum": "64b1e81cd54008318235832ea6d71424", + "filesize": 2959736832, + "download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/" + } ], "versions": [ { - "name": "6.1.0 (ESX)", + "name": "8.1.0 (ESX)", "images": { - "hda_disk_image": "PA-VM-ESX-6.1.0-disk1.vmdk" + "hda_disk_image": "PA-VM-ESX-8.1.0-disk1.vmdk" } - }, + }, { - "name": "7.1.0", + "name": "8.1.0", "images": { - "hda_disk_image": "PA-VM-KVM-7.1.0.qcow2" + "hda_disk_image": "PA-VM-KVM-8.1.0.qcow2" } - }, + }, { - "name": "7.1.0 (ESX)", + "name": "8.0.0 (ESX)", "images": { - "hda_disk_image": "PA-VM-ESX-7.1.0-disk1.vmdk" + "hda_disk_image": "PA-VM-ESX-8.0.0-disk1.vmdk2" } }, { @@ -80,6 +100,24 @@ "images": { "hda_disk_image": "PA-VM-KVM-8.0.0.qcow2" } - } + }, + { + "name": "7.1.0 (ESX)", + "images": { + "hda_disk_image": "PA-VM-ESX-7.1.0-disk1.vmdk" + } + }, + { + "name": "7.1.0", + "images": { + "hda_disk_image": "PA-VM-KVM-7.1.0.qcow2" + } + }, + { + "name": "6.1.0 (ESX)", + "images": { + "hda_disk_image": "PA-VM-ESX-6.1.0-disk1.vmdk" + } + } ] } diff --git a/gns3server/appliances/vyos.gns3a b/gns3server/appliances/vyos.gns3a index fc68dedd..7e3cd601 100644 --- a/gns3server/appliances/vyos.gns3a +++ b/gns3server/appliances/vyos.gns3a @@ -80,6 +80,13 @@ "cdrom_image": "vyos-1.2.0-beta1-amd64.iso" } }, + { + "name": "1.1.8", + "images": { + "hda_disk_image": "empty8G.qcow2", + "cdrom_image": "vyos-1.1.8-amd64.iso" + } + }, { "name": "1.1.7", "images": { From fff2e128ebafaf51d49ca55bba16fe14344753ee Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 18 Apr 2018 16:06:51 +0800 Subject: [PATCH 10/12] Set the first byte to 0C when generating a random MAC address for a Qemu VM. Ref #1267. --- gns3server/compute/qemu/qemu_vm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index 7aeaf446..95d414fe 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -533,7 +533,7 @@ class QemuVM(BaseNode): if not mac_address: # use the node UUID to generate a random MAC address - self._mac_address = "52:%s:%s:%s:%s:00" % (self.project.id[-4:-2], self.project.id[-2:], self.id[-4:-2], self.id[-2:]) + self._mac_address = "0C:%s:%s:%s:%s:00" % (self.project.id[-4:-2], self.project.id[-2:], self.id[-4:-2], self.id[-2:]) else: self._mac_address = mac_address From 013c74f6d8c2c0435eee5734dd8a4a49f6672f3e Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 18 Apr 2018 16:12:30 +0800 Subject: [PATCH 11/12] Sync appliance files. --- gns3server/appliances/mikrotik-chr.gns3a | 9 ++++++ gns3server/appliances/ubuntu-cloud.gns3a | 38 ++++++++---------------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/gns3server/appliances/mikrotik-chr.gns3a b/gns3server/appliances/mikrotik-chr.gns3a index c57d80e5..fefae16a 100644 --- a/gns3server/appliances/mikrotik-chr.gns3a +++ b/gns3server/appliances/mikrotik-chr.gns3a @@ -26,6 +26,15 @@ "options": "-nographic" }, "images": [ + { + "filename": "chr-6.42.img", + "version": "6.42", + "md5sum": "279bb518497b40f41c8585128916a2fb", + "filesize": 134217728, + "download_url": "http://www.mikrotik.com/download", + "direct_download_url": "https://download2.mikrotik.com/routeros/6.42/chr-6.42.img.zip", + "compression": "zip" + }, { "filename": "chr-6.41.4.img", "version": "6.41.4", diff --git a/gns3server/appliances/ubuntu-cloud.gns3a b/gns3server/appliances/ubuntu-cloud.gns3a index e8bb8040..d2766b07 100644 --- a/gns3server/appliances/ubuntu-cloud.gns3a +++ b/gns3server/appliances/ubuntu-cloud.gns3a @@ -28,37 +28,30 @@ { "filename": "ubuntu-17.10-server-cloudimg-amd64.img", "version": "17.10", - "md5sum": "5d221878d8b2e49c5de7ebb58a2b35e3", - "filesize": 318373888, - "download_url": "https://cloud-images.ubuntu.com/releases/17.10/release/" - }, - { - "filename": "ubuntu-17.04-server-cloudimg-amd64.img", - "version": "17.04", - "md5sum": "d4da8157dbf2e64f2fa1fb5d121398e5", - "filesize": 351993856, - "download_url": "https://cloud-images.ubuntu.com/releases/17.04/release/" + "md5sum": "331b44f2b05858c251b3ea92c8b65152", + "filesize": 320405504, + "download_url": "https://cloud-images.ubuntu.com/releases/17.10/release-20180404/ubuntu-17.10-server-cloudimg-amd64.img" }, { "filename": "ubuntu-16.04-server-cloudimg-amd64-disk1.img", - "version": "16.04.3", - "md5sum": "bd0c168a83b1f483bd240b3d874edd6c", - "filesize": 288686080, - "download_url": "https://cloud-images.ubuntu.com/releases/16.04/release/" + "version": "16.04", + "md5sum": "22c124ba65ea096cdef8b0a197dd613a", + "filesize": 290193408, + "download_url": "https://cloud-images.ubuntu.com/releases/16.04/release-20180405/ubuntu-16.04-server-cloudimg-amd64-disk1.img" }, { "filename": "ubuntu-14.04-server-cloudimg-amd64-disk1.img", - "version": "14.04.5", - "md5sum": "d7b4112c7d797e5e77ef9995d06a76f1", - "filesize": 262406656, - "download_url": "https://cloud-images.ubuntu.com/releases/14.04/release/" + "version": "14.04", + "md5sum": "d11b89321d41d0eeddcacf73bf0d2262", + "filesize": 262668800, + "download_url": "https://cloud-images.ubuntu.com/releases/14.04/release-20180404/ubuntu-14.04-server-cloudimg-amd64-disk1.img" }, { "filename": "ubuntu-cloud-init-data.iso", "version": "1.0", "md5sum": "328469100156ae8dbf262daa319c27ff", "filesize": 131072, - "download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/ubuntu-cloud-init-data.iso/download" + "download_url": "https://github.com/asenci/gns3-ubuntu-cloud-init-data/raw/master/ubuntu-cloud-init-data.iso" } ], "versions": [ @@ -69,13 +62,6 @@ "cdrom_image": "ubuntu-cloud-init-data.iso" } }, - { - "name": "17.04", - "images": { - "hda_disk_image": "ubuntu-17.04-server-cloudimg-amd64.img", - "cdrom_image": "ubuntu-cloud-init-data.iso" - } - }, { "name": "16.04 (LTS)", "images": { From 9ecb058343bee18244b5354bb4e7f5133c2e3a4d Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 18 Apr 2018 16:13:59 +0800 Subject: [PATCH 12/12] Fix tests. --- gns3server/compute/qemu/qemu_vm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index 95d414fe..894cad8c 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -533,7 +533,7 @@ class QemuVM(BaseNode): if not mac_address: # use the node UUID to generate a random MAC address - self._mac_address = "0C:%s:%s:%s:%s:00" % (self.project.id[-4:-2], self.project.id[-2:], self.id[-4:-2], self.id[-2:]) + self._mac_address = "0c:%s:%s:%s:%s:00" % (self.project.id[-4:-2], self.project.id[-2:], self.id[-4:-2], self.id[-2:]) else: self._mac_address = mac_address