diff --git a/CHANGELOG b/CHANGELOG index af346bc47..b8b84930a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,13 @@ # Change Log +## 2.2.44 06/11/2023 + +* Fix timeout issue when creating Qemu disk image. Fixes https://github.com/GNS3/gns3-server/issues/2313 +* Refactor command variables support +* Add vendor_logo_url in appliance schemas. Ref https://github.com/GNS3/gns3-registry/pull/825 +* Add Qemu IGB network device +* Add the ability to edit width and height in the style edit dialog. + ## 2.2.43 19/09/2023 * Add KiTTY to preconfigured telnet consoles. Fixes #3507 diff --git a/appveyor.yml b/appveyor.yml index b6ee34cee..61e9697fb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ image: Visual Studio 2022 platform: x64 environment: - PYTHON: "C:\\Python37-x64" + PYTHON: "C:\\Python38-x64" DISTUTILS_USE_SDK: "1" install: diff --git a/gns3/crash_report.py b/gns3/crash_report.py index 51ff5692e..eaa4e3984 100644 --- a/gns3/crash_report.py +++ b/gns3/crash_report.py @@ -50,7 +50,7 @@ class CrashReport: Report crash to a third party service """ - DSN = "https://57454675a266a9d705fd505947a81b5c@o19455.ingest.sentry.io/38506" + DSN = "https://5c5fb544e56f9d41179e57bfff78e151@o19455.ingest.sentry.io/38506" _instance = None def __init__(self): diff --git a/gns3/local_server.py b/gns3/local_server.py index 9c52a1daa..0031c3754 100644 --- a/gns3/local_server.py +++ b/gns3/local_server.py @@ -482,11 +482,15 @@ def startLocalServer(self): try: if sys.platform.startswith("win"): # use the string on Windows - self._local_server_process = subprocess.Popen(command, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, stderr=subprocess.PIPE) + self._local_server_process = subprocess.Popen( + command, + creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, + stderr=subprocess.PIPE, + env=os.environ) else: # use arguments on other platforms args = shlex.split(command) - self._local_server_process = subprocess.Popen(args, stderr=subprocess.PIPE) + self._local_server_process = subprocess.Popen(args, stderr=subprocess.PIPE, env=os.environ) except (OSError, subprocess.SubprocessError) as e: log.warning('Could not start local server "{}": {}'.format(command, e)) return False diff --git a/gns3/modules/qemu/__init__.py b/gns3/modules/qemu/__init__.py index 3275df031..508d18fe6 100644 --- a/gns3/modules/qemu/__init__.py +++ b/gns3/modules/qemu/__init__.py @@ -121,7 +121,7 @@ def createDiskImage(self, compute_id, callback, options): :param options: Options for the image creation """ - Controller.instance().postCompute("/qemu/img", compute_id, callback, body=options) + Controller.instance().postCompute("/qemu/img", compute_id, callback, timeout=None, body=options) def updateDiskImage(self, compute_id, callback, options): """ diff --git a/gns3/modules/qemu/pages/qemu_vm_configuration_page.py b/gns3/modules/qemu/pages/qemu_vm_configuration_page.py index a6aac05b0..439009d1f 100644 --- a/gns3/modules/qemu/pages/qemu_vm_configuration_page.py +++ b/gns3/modules/qemu/pages/qemu_vm_configuration_page.py @@ -101,7 +101,7 @@ def __init__(self): self.uiOnCloseComboBox.addItem(name, option_name) # Supported NIC models: e1000, e1000-82544gc, e1000-82545em, e1000e, i82550, i82551, i82557a, i82557b, i82557c, i82558a - # i82558b, i82559a, i82559b, i82559c, i82559er, i82562, i82801, ne2k_pci, pcnet, rocker, rtl8139, virtio-net-pci, vmxnet3 + # i82558b, i82559a, i82559b, i82559c, i82559er, i82562, i82801, igb, ne2k_pci, pcnet, rocker, rtl8139, virtio-net-pci, vmxnet3 # This list can be retrieved using "qemu-system-x86_64 -nic model=?" or "qemu-system-x86_64 -device help" self._legacy_devices = ("e1000", "i82551", "i82557b", "i82559er", "ne2k_pci", "pcnet", "rtl8139", "virtio") self._qemu_network_devices = OrderedDict([("e1000", "Intel Gigabit Ethernet"), @@ -121,6 +121,7 @@ def __init__(self): ("i82559er", "Intel i82559ER Ethernet"), ("i82562", "Intel i82562 Ethernet"), ("i82801", "Intel i82801 Ethernet"), + ("igb", "Intel 82576 Gigabit Ethernet"), ("ne2k_pci", "NE2000 Ethernet"), ("pcnet", "AMD PCNet Ethernet"), ("rocker", "Rocker L2 switch device"), diff --git a/gns3/packet_capture.py b/gns3/packet_capture.py index 04d3a5e15..cc317985a 100644 --- a/gns3/packet_capture.py +++ b/gns3/packet_capture.py @@ -146,13 +146,19 @@ def startPacketCaptureAnalyzer(self, link): # PCAP capture file path command = command.replace("%c", '"' + capture_file_path + '"') + command = command.replace("{pcap_file}", '"' + capture_file_path + '"') - # Add description + # Add project name + command = command.replace("%P", link.project().name()) + command = command.replace("{project}", link.project().name().replace('"', '\\"')) + + # Add link description description = "{}[{}]->{}[{}]".format(link.sourceNode().name(), link.sourcePort().name(), link.destinationNode().name(), link.destinationPort().name()) command = command.replace("%d", description) + command = command.replace("{link_description}", description) if not sys.platform.startswith("win"): command = shlex.split(command) @@ -160,7 +166,7 @@ def startPacketCaptureAnalyzer(self, link): QtWidgets.QMessageBox.critical(self.parent(), "Packet Capture Analyzer", "No packet capture analyzer program configured") return try: - subprocess.Popen(command) + subprocess.Popen(command, env=os.environ) except OSError as e: QtWidgets.QMessageBox.critical(self.parent(), "Packet Capture Analyzer", "Can't start packet capture analyzer program {}".format(str(e))) return @@ -204,13 +210,19 @@ def _startPacketCommand(self, link, command): # PCAP capture file path command = command.replace("%c", '"' + capture_file_path + '"') + command = command.replace("{pcap_file}", '"' + capture_file_path + '"') + + # Add project name + command = command.replace("%P", link.project().name()) + command = command.replace("{project}", link.project().name().replace('"', '\\"')) - # Add description + # Add link description description = "{} {} to {} {}".format(link.sourceNode().name(), link.sourcePort().name(), link.destinationNode().name(), link.destinationPort().name()) command = command.replace("%d", description) + command = command.replace("{link_description}", description) if "|" in command: # live traffic capture (using tail) diff --git a/gns3/schemas/appliance.json b/gns3/schemas/appliance.json index 78b7c004a..1b57db8f2 100644 --- a/gns3/schemas/appliance.json +++ b/gns3/schemas/appliance.json @@ -287,6 +287,7 @@ "i82559er", "i82562", "i82801", + "igb", "ne2k_pci", "pcnet", "rocker", diff --git a/gns3/schemas/appliance_v8.json b/gns3/schemas/appliance_v8.json index e120c8313..55c245b57 100644 --- a/gns3/schemas/appliance_v8.json +++ b/gns3/schemas/appliance_v8.json @@ -356,6 +356,7 @@ "i82559er", "i82562", "i82801", + "igb", "ne2k_pci", "pcnet", "rtl8139", @@ -402,6 +403,7 @@ "i82559er", "i82562", "i82801", + "igb", "ne2k_pci", "pcnet", "rtl8139", diff --git a/gns3/settings.py b/gns3/settings.py index c8df8aca7..42e655019 100644 --- a/gns3/settings.py +++ b/gns3/settings.py @@ -55,29 +55,29 @@ # windows 32-bit program_files_x86 = program_files = os.environ["PROGRAMFILES"] - PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Putty (normal standalone version)': 'putty_standalone.exe -telnet %h %p -loghost "%d"', - 'KiTTY': r'kitty -title "%d" telnet://%h %p', - 'MobaXterm': r'"{}\Mobatek\MobaXterm Personal Edition\MobaXterm.exe" -newtab "telnet %h %p"'.format(program_files_x86), - 'Royal TS V3': r'{}\code4ward.net\Royal TS V3\RTS3App.exe /connectadhoc:%h /adhoctype:terminal /p:IsTelnetConnection="true" /p:ConnectionType="telnet;Telnet Connection" /p:Port="%p" /p:Name="%d"'.format(program_files), - 'Royal TS V5': r'"{}\Royal TS V5\RoyalTS.exe" /protocol:terminal /using:adhoc /uri:"%h" /property:Port="%p" /property:IsTelnetConnection="true" /property:Name="%d"'.format(program_files_x86), - 'SuperPutty': r'SuperPutty.exe -telnet "%h -P %p -wt \"%d\""', - 'SecureCRT': r'"{}\VanDyke Software\SecureCRT\SecureCRT.exe" /N "%d" /T /TELNET %h %p'.format(program_files), - 'SecureCRT (personal profile)': r'"{}\AppData\Local\VanDyke Software\SecureCRT\SecureCRT.exe" /T /N "%d" /TELNET %h %p'.format(userprofile), - 'TeraTerm Pro': r'"{}\teraterm\ttermpro.exe" /W="%d" /M="ttstart.macro" /T=1 %h %p'.format(program_files_x86), - 'Telnet': 'telnet %h %p', - 'Windows Terminal': 'wt.exe -w 1 new-tab --title %d telnet %h %p', - 'Xshell 4': r'"{}\NetSarang\Xshell 4\xshell.exe" -url telnet://%h:%p'.format(program_files_x86), - 'Xshell 5': r'"{}\NetSarang\Xshell 5\xshell.exe" -url telnet://%h:%p -newtab %d'.format(program_files_x86), - 'ZOC 6': r'"{}\ZOC6\zoc.exe" "/TELNET:%h:%p" /TABBED "/TITLE:%d"'.format(program_files_x86)} + PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Putty (normal standalone version)': 'putty_standalone.exe -telnet {host} {port} -loghost "{name}"', + 'KiTTY': r'kitty -title "{name}" telnet://{host} {port}', + 'MobaXterm': r'"{}\Mobatek\MobaXterm Personal Edition\MobaXterm.exe" -newtab "telnet {{host}} {{port}}"'.format(program_files_x86), + 'Royal TS V3': r'{}\code4ward.net\Royal TS V3\RTS3App.exe /connectadhoc:{{host}} /adhoctype:terminal /p:IsTelnetConnection="true" /p:ConnectionType="telnet;Telnet Connection" /p:Port="{{port}}" /p:Name="{{name}}"'.format(program_files), + 'Royal TS V5': r'"{}\Royal TS V5\RoyalTS.exe" /protocol:terminal /using:adhoc /uri:"{{host}}" /property:Port="{{port}}" /property:IsTelnetConnection="true" /property:Name="{{name}}"'.format(program_files_x86), + 'SuperPutty': r'SuperPutty.exe -telnet "{host} -P {port} -wt \"{name}\""', + 'SecureCRT': r'"{}\VanDyke Software\SecureCRT\SecureCRT.exe" /N "{{name}}" /T /TELNET {{host}} {{port}}'.format(program_files), + 'SecureCRT (personal profile)': r'"{}\AppData\Local\VanDyke Software\SecureCRT\SecureCRT.exe" /T /N "{{name}}" /TELNET {{host}} {{port}}'.format(userprofile), + 'TeraTerm Pro': r'"{}\teraterm\ttermpro.exe" /W="{{name}}" /M="ttstart.macro" /T=1 {{host}} {{port}}'.format(program_files_x86), + 'Telnet': 'telnet {host} {port}', + 'Windows Terminal': 'wt.exe -w 1 new-tab --title {name} telnet {host} {port}', + 'Xshell 4': r'"{}\NetSarang\Xshell 4\xshell.exe" -url telnet://{{host}}:{{port}}'.format(program_files_x86), + 'Xshell 5': r'"{}\NetSarang\Xshell 5\xshell.exe" -url telnet://{{host}}:{{port}} -newtab {{name}}'.format(program_files_x86), + 'ZOC 6': r'"{}\ZOC6\zoc.exe" "/TELNET:{{host}}:{{port}}" /TABBED "/TITLE:{{name}}"'.format(program_files_x86)} # default on Windows if shutil.which("Solar-PuTTY.exe"): # Solar-Putty is the default if it is installed. - PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3)"] = 'Solar-PuTTY.exe --telnet --hostname %h --port %p --name "%d"' + PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3)"] = 'Solar-PuTTY.exe --telnet --hostname {host} --port {port} --name "{name}"' DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3)"] DEFAULT_DELAY_CONSOLE_ALL = 1500 else: - PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3 downloaded from gns3.com)"] = 'Solar-PuTTY.exe --telnet --hostname %h --port %p --name "%d"' + PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3 downloaded from gns3.com)"] = 'Solar-PuTTY.exe --telnet --hostname {host} --port {port} --name "{name}"' DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Putty (normal standalone version)"] elif sys.platform.startswith("darwin"): @@ -87,7 +87,7 @@ r""" -e 'set posix_path to do shell script "echo \"$PATH\""'""" r""" -e 'tell application "Terminal"'""" r""" -e 'activate'""" - r""" -e 'do script "echo -n -e \"\\033]0;%d\\007\"; clear; PATH=" & quoted form of posix_path & " telnet %h %p ; exit"'""" + r""" -e 'do script "echo -n -e \"\\033]0;{name}\\007\"; clear; PATH=" & quoted form of posix_path & " telnet {host} {port} ; exit"'""" r""" -e 'end tell'""", 'Terminal tabbed (experimental)': r"""osascript""" r""" -e 'set posix_path to do shell script "echo \"$PATH\""'""" @@ -103,7 +103,7 @@ r""" -e 'repeat while the busy of window 1 = true'""" r""" -e 'delay 0.01'""" r""" -e 'end repeat'""" - r""" -e 'do script "echo -n -e \"\\033]0;%d\\007\"; clear; PATH=" & quoted form of posix_path & " telnet %h %p ; exit" in window 1'""" + r""" -e 'do script "echo -n -e \"\\033]0;{name}\\007\"; clear; PATH=" & quoted form of posix_path & " telnet {host} {port} ; exit" in window 1'""" r""" -e 'end tell'""", 'iTerm2 2.x': r"""osascript""" r""" -e 'set posix_path to do shell script "echo \"$PATH\""'""" @@ -118,7 +118,7 @@ r""" -e ' set s to (make new session at the end of sessions)'""" r""" -e ' tell s'""" r""" -e ' exec command "sh"'""" - r""" -e ' write text "PATH=" & quoted form of posix_path & " exec telnet %h %p"'""" + r""" -e ' write text "PATH=" & quoted form of posix_path & " exec telnet {host} {port}"'""" r""" -e ' end tell'""" r""" -e 'end tell'""" r""" -e 'end tell'""", @@ -135,33 +135,33 @@ r""" -e ' create tab with default profile command "sh"'""" r""" -e ' set s to current session'""" r""" -e ' tell s'""" - r""" -e ' set name to "%d"'""" - r""" -e ' write text "PATH=" & quoted form of posix_path & " exec telnet %h %p"'""" + r""" -e ' set name to "{name}"'""" + r""" -e ' write text "PATH=" & quoted form of posix_path & " exec telnet {host} {port}"'""" r""" -e ' end tell'""" r""" -e 'end tell'""" r""" -e 'end tell'""", - 'Royal TSX': "open 'rtsx://telnet%3A%2F%2F%h:%p'", - 'SecureCRT': '/Applications/SecureCRT.app/Contents/MacOS/SecureCRT /N "%d" /T /TELNET %h %p', - 'ZOC 6': '/Applications/zoc6.app/Contents/MacOS/zoc6 "/TELNET:%h:%p" /TABBED "/TITLE:%d"', - 'ZOC 7': '/Applications/zoc7.app/Contents/MacOS/zoc7 "/TELNET:%h:%p" /TABBED "/TITLE:%d"', - 'ZOC 8': '/Applications/zoc8.app/Contents/MacOS/zoc8 "/TELNET:%h:%p" /TABBED "/TITLE:%d"' + 'Royal TSX': "open 'rtsx://telnet%3A%2F%2F{host}:{port}'", + 'SecureCRT': '/Applications/SecureCRT.app/Contents/MacOS/SecureCRT /N "{name}" /T /TELNET {host} {port}', + 'ZOC 6': '/Applications/zoc6.app/Contents/MacOS/zoc6 "/TELNET:{host}:{port}" /TABBED "/TITLE:{name}"', + 'ZOC 7': '/Applications/zoc7.app/Contents/MacOS/zoc7 "/TELNET:{host}:{port}" /TABBED "/TITLE:{name}"', + 'ZOC 8': '/Applications/zoc8.app/Contents/MacOS/zoc8 "/TELNET:{host}:{port}" /TABBED "/TITLE:{name}"' } # default Mac OS X Telnet console command DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Terminal"] else: - PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Xterm': 'xterm -T "%d" -e "telnet %h %p"', - 'Putty': 'putty -telnet %h %p -title "%d" -sl 2500 -fg SALMON1 -bg BLACK', - 'Gnome Terminal': 'gnome-terminal --tab -t "%d" -- telnet %h %p', - 'Xfce4 Terminal': 'xfce4-terminal --tab -T "%d" -e "telnet %h %p"', - 'ROXTerm': 'roxterm -n "%d" --tab -e "telnet %h %p"', - 'KDE Konsole': 'konsole --new-tab -p tabtitle="%d" -e "telnet %h %p"', - 'SecureCRT': 'SecureCRT /T /N "%d" /TELNET %h %p', - 'Mate Terminal': 'mate-terminal --tab -e "telnet %h %p" -t "%d"', - 'terminator': 'terminator -e "telnet %h %p" -T "%d"', - 'urxvt': 'urxvt -title %d -e telnet %h %p', - 'kitty': 'kitty -T %d telnet %h %p'} + PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Xterm': 'xterm -T "{name}" -e "telnet {host} {port}"', + 'Putty': 'putty -telnet {host} {port} -title "{name}" -sl 2500 -fg SALMON1 -bg BLACK', + 'Gnome Terminal': 'gnome-terminal --tab -t "{name}" -- telnet {host} {port}', + 'Xfce4 Terminal': 'xfce4-terminal --tab -T "{name}" -e "telnet {host} {port}"', + 'ROXTerm': 'roxterm -n "{name}" --tab -e "telnet {host} {port}"', + 'KDE Konsole': 'konsole --new-tab -p tabtitle="{name}" -e "telnet {host} {port}"', + 'SecureCRT': 'SecureCRT /T /N "{name}" /TELNET {host} {port}', + 'Mate Terminal': 'mate-terminal --tab -e "telnet {host} {port}" -t "{name}"', + 'terminator': 'terminator -e "telnet {host} {port}" -T "{name}"', + 'urxvt': 'urxvt -title {name} -e telnet {host} {port}', + 'kitty': 'kitty -T {name} telnet {host} {port}'} # default Telnet console command on other systems DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Xterm"] @@ -178,8 +178,8 @@ if sys.platform.startswith("win"): # Windows PRECONFIGURED_VNC_CONSOLE_COMMANDS = { - 'TightVNC (included with GNS3)': 'tvnviewer.exe %h:%p', - 'UltraVNC': r'"{}\uvnc bvba\UltraVNC\vncviewer.exe" %h:%p'.format(program_files) + 'TightVNC (included with GNS3)': 'tvnviewer.exe {host}:{port}', + 'UltraVNC': r'"{}\uvnc bvba\UltraVNC\vncviewer.exe" {{host}}:{{port}}'.format(program_files) } # default Windows VNC console command @@ -191,11 +191,11 @@ 'OSX builtin screen sharing': "osascript" " -e 'tell application \"Screen Sharing\"'" " -e ' display dialog \"WARNING OSX VNC support is limited if you have trouble connecting to a device please use an alternative client like Chicken of the VNC.\" buttons {\"OK\"} default button 1 with icon caution with title \"GNS3\"'" - " -e ' open location \"vnc://%h:%p\"'" + " -e ' open location \"vnc://{host}:{port}\"'" " -e 'end tell'", - 'Chicken of the VNC': "/Applications/Chicken.app/Contents/MacOS/Chicken %h:%p", - 'Chicken of the VNC < 2.2': r"/Applications/Chicken\ of\ the\ VNC.app/Contents/MacOS/Chicken\ of\ the\ VNC %h:%p", - 'Royal TSX': "open 'rtsx://vnc%3A%2F%2F%h:%p'", + 'Chicken of the VNC': "/Applications/Chicken.app/Contents/MacOS/Chicken {host}:{port}", + 'Chicken of the VNC < 2.2': r"/Applications/Chicken\ of\ the\ VNC.app/Contents/MacOS/Chicken\ of\ the\ VNC {host}:{port}", + 'Royal TSX': "open 'rtsx://vnc%3A%2F%2F{host}:{port}'", } # default Mac OS X VNC console command @@ -203,10 +203,10 @@ else: PRECONFIGURED_VNC_CONSOLE_COMMANDS = { - 'TightVNC': 'vncviewer %h:%p', - 'Vinagre': 'vinagre %h::%p', - 'gvncviewer': 'gvncviewer %h:%P', - 'Remote Viewer': 'remote-viewer vnc://%h:%p' + 'TightVNC': 'vncviewer {host}:{port}', + 'Vinagre': 'vinagre {host}::{port}', + 'gvncviewer': 'gvncviewer {host}:{display}', + 'Remote Viewer': 'remote-viewer vnc://{host}:{port}' } # default VNC console command on other systems @@ -216,7 +216,7 @@ if sys.platform.startswith("win"): # Windows PRECONFIGURED_SPICE_CONSOLE_COMMANDS = { - 'Remote Viewer': r'"{}\VirtViewer v11.0-256\bin\remote-viewer.exe" spice://%h:%p'.format(program_files), + 'Remote Viewer': r'"{}\VirtViewer v11.0-256\bin\remote-viewer.exe" spice://{{host}}:{{port}}'.format(program_files), } # default Windows SPICE console command @@ -225,7 +225,7 @@ elif sys.platform.startswith("darwin"): # Mac OS X PRECONFIGURED_SPICE_CONSOLE_COMMANDS = { - 'Remote Viewer': '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer spice://%h:%p', + 'Remote Viewer': '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer spice://{host}:{port}', } # default Mac OS X SPICE console command @@ -233,7 +233,7 @@ else: PRECONFIGURED_SPICE_CONSOLE_COMMANDS = { - 'Remote Viewer': 'remote-viewer spice://%h:%p', + 'Remote Viewer': 'remote-viewer spice://{host}:{port}', } # default SPICE console command on other systems @@ -244,29 +244,28 @@ WIRESHARK_LIVE_TRAFFIC_CAPTURE = "Wireshark Live Traffic Capture" if sys.platform.startswith("win"): - PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: r"{}\Wireshark\wireshark.exe %c".format(program_files), - WIRESHARK_LIVE_TRAFFIC_CAPTURE: r'tail.exe -f -c +0b %c | "{}\Wireshark\wireshark.exe" -o "gui.window_title:%d" -k -i -'.format(program_files)} + PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: r'{}\Wireshark\wireshark.exe {{pcap_file}} --capture-comment "{{project}} {{link_description}}"'.format(program_files), + WIRESHARK_LIVE_TRAFFIC_CAPTURE: r'tail.exe -f -c +0b {{pcap_file}} | "{}\Wireshark\wireshark.exe" --capture-comment "{{project}} {{link_description}}" -o "gui.window_title:{{link_description}}" -k -i -'.format(program_files)} elif sys.platform.startswith("darwin"): # Mac OS X - PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: "/usr/bin/open -a /Applications/Wireshark.app %c", - "Wireshark V1.X Live Traffic Capture": 'tail -f -c +0 %c | /Applications/Wireshark.app/Contents/Resources/bin/wireshark -o "gui.window_title:%d" -k -i -', - WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail -f -c +0 %c | /Applications/Wireshark.app/Contents/MacOS/Wireshark -o "gui.window_title:%d" -k -i -'} + PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: '/usr/bin/open -a /Applications/Wireshark.app {pcap_file} --capture-comment {project} {link_description}"', + WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail -f -c +0 {pcap_file} | /Applications/Wireshark.app/Contents/MacOS/Wireshark --capture-comment "{project} {link_description}" -o "gui.window_title:{link_description}" -k -i -'} elif sys.platform.startswith("freebsd"): # FreeBSD - PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: "wireshark %c", - WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'gtail -f -c +0b %c | wireshark -o "gui.window_title:%d" -k -i -'} + PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: 'wireshark {pcap_file} --capture-comment "{project} {link_description}"', + WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'gtail -f -c +0b {pcap_file} | wireshark --capture-comment "{project} {link_description}" -o "gui.window_title:{link_description}" -k -i -'} else: - PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: "wireshark %c", - WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail -f -c +0b %c | wireshark -o "gui.window_title:%d" -k -i -'} + PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: 'wireshark {pcap_file} --capture-comment "{project} {link_description}"', + WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail -f -c +0b {pcap_file} | wireshark --capture-comment "{project} {link_description}" -o "gui.window_title:{link_description}" -k -i -'} DEFAULT_PACKET_CAPTURE_READER_COMMAND = PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS[WIRESHARK_LIVE_TRAFFIC_CAPTURE] DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND = "" if sys.platform.startswith("win"): # Windows 64-bit - DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND = r'"{}\SolarWinds\ResponseTimeViewer\ResponseTimeViewer.exe" %c'.format(program_files_x86) + DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND = r'"{}\SolarWinds\ResponseTimeViewer\ResponseTimeViewer.exe" {{pcap_file}}'.format(program_files_x86) STYLES = ["Charcoal", "Classic", "Legacy"] diff --git a/gns3/spice_console.py b/gns3/spice_console.py index bad10f634..88739b22a 100644 --- a/gns3/spice_console.py +++ b/gns3/spice_console.py @@ -54,14 +54,24 @@ def spiceConsole(node, port, command): command = command.replace("%h", host) command = command.replace("%p", str(port)) command = command.replace("%d", name.replace('"', '\\"')) + command = command.replace("%P", node.project().name().replace('"', '\\"')) command = command.replace("%i", node.project().id()) command = command.replace("%n", str(node.id())) + command = command.replace("%c", Controller.instance().httpClient().fullUrl()) + + command = command.replace("{host}", host) + command = command.replace("{port}", str(port)) + command = command.replace("{name}", name.replace('"', '\\"')) + command = command.replace("{project}", node.project().name()) + command = command.replace("{project_id}", node.project().id()) + command = command.replace("{node_id}", str(node.id())) + command = command.replace("{url}", Controller.instance().httpClient().fullUrl()) try: log.debug('starting SPICE program "{}"'.format(command)) if sys.platform.startswith("win"): # use the string on Windows - subprocess.Popen(command) + subprocess.Popen(command, env=os.environ) else: # use arguments on other platforms args = shlex.split(command) diff --git a/gns3/telnet_console.py b/gns3/telnet_console.py index eed6619ad..46660438d 100644 --- a/gns3/telnet_console.py +++ b/gns3/telnet_console.py @@ -87,7 +87,7 @@ def exec_command(self, command): if sys.platform.startswith("win"): # use the string on Windows - subprocess.call(command) + subprocess.Popen(command, env=os.environ) else: # use arguments on other platforms try: @@ -102,7 +102,7 @@ def exec_command(self, command): # inject gnome-terminal environment variables if "GNOME_TERMINAL_SERVICE" not in env or "GNOME_TERMINAL_SCREEN" not in env: env.update(gnome_terminal_env()) - subprocess.call(args, env=env) + subprocess.Popen(args, env=env) def run(self): @@ -113,10 +113,19 @@ def run(self): command = self._command.replace("%h", host) command = command.replace("%p", str(port)) command = command.replace("%d", self._name.replace('"', '\\"')) + command = command.replace("%P", self._node.project().name().replace('"', '\\"')) command = command.replace("%i", self._node.project().id()) command = command.replace("%n", str(self._node.id())) command = command.replace("%c", Controller.instance().httpClient().fullUrl()) + command = command.replace("{host}", host) + command = command.replace("{port}", str(port)) + command = command.replace("{name}", self._name.replace('"', '\\"')) + command = command.replace("{project}", self._node.project().name().replace('"', '\\"')) + command = command.replace("{project_id}", self._node.project().id()) + command = command.replace("{node_id}", str(self._node.id())) + command = command.replace("{url}", Controller.instance().httpClient().fullUrl()) + # If the console use an apple script we lock to avoid multiple console # to interact at the same time if sys.platform.startswith("darwin") and "osascript" in command: diff --git a/gns3/ui/console_command_dialog.ui b/gns3/ui/console_command_dialog.ui index efc6b3fb9..f34d38856 100644 --- a/gns3/ui/console_command_dialog.ui +++ b/gns3/ui/console_command_dialog.ui @@ -6,8 +6,8 @@ 0 0 - 965 - 547 + 576 + 346 @@ -70,7 +70,7 @@ - <html><head/><body><p>Or customize the command in the next input field. <br/>The following variables are replaced by GNS3: </p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h: console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p: console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P: VNC display</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%s: path of the serial connection</li></ul><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d: title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i: Project UUID</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c: server URL (<span style=" font-style:italic;">http://user:password@server:port</span>)</li></ul></body></html> + <html><head/><body><p>Or customize the command in the next input field. <br/>The following variables are replaced by GNS3: </p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h or {host}: console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p or {port}: console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%D or {display}: VNC display</li></ul><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d or {name}: title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P or {project}: project name</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i or {project_id}: project UUID</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c or {url}: server URL (<span style=" font-style:italic;">http://user:password@server:port</span>)</li></ul></body></html> Qt::RichText diff --git a/gns3/ui/console_command_dialog_ui.py b/gns3/ui/console_command_dialog_ui.py index d5af4e04d..18542d388 100644 --- a/gns3/ui/console_command_dialog_ui.py +++ b/gns3/ui/console_command_dialog_ui.py @@ -2,16 +2,19 @@ # Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/console_command_dialog.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt5 UI code generator 5.15.6 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + from PyQt5 import QtCore, QtGui, QtWidgets + class Ui_uiConsoleCommandDialog(object): def setupUi(self, uiConsoleCommandDialog): uiConsoleCommandDialog.setObjectName("uiConsoleCommandDialog") - uiConsoleCommandDialog.resize(965, 547) + uiConsoleCommandDialog.resize(576, 346) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -57,8 +60,8 @@ def setupUi(self, uiConsoleCommandDialog): self.verticalLayout.addWidget(self.uiButtonBox) self.retranslateUi(uiConsoleCommandDialog) - self.uiButtonBox.accepted.connect(uiConsoleCommandDialog.accept) - self.uiButtonBox.rejected.connect(uiConsoleCommandDialog.reject) + self.uiButtonBox.accepted.connect(uiConsoleCommandDialog.accept) # type: ignore + self.uiButtonBox.rejected.connect(uiConsoleCommandDialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(uiConsoleCommandDialog) def retranslateUi(self, uiConsoleCommandDialog): @@ -67,5 +70,4 @@ def retranslateUi(self, uiConsoleCommandDialog): self.label_2.setText(_translate("uiConsoleCommandDialog", "Choose a predefined command:")) self.uiRemovePushButton.setText(_translate("uiConsoleCommandDialog", "Remove")) self.uiSavePushButton.setText(_translate("uiConsoleCommandDialog", "Save")) - self.label.setText(_translate("uiConsoleCommandDialog", "

Or customize the command in the next input field.
The following variables are replaced by GNS3:

  • %h: console IP or hostname
  • %p: console port
  • %P: VNC display
  • %s: path of the serial connection
  • %d: title of the console
  • %i: Project UUID
  • %c: server URL (http://user:password@server:port)
")) - + self.label.setText(_translate("uiConsoleCommandDialog", "

Or customize the command in the next input field.
The following variables are replaced by GNS3:

  • %h or {host}: console IP or hostname
  • %p or {port}: console port
  • %D or {display}: VNC display
  • %d or {name}: title of the console
  • %P or {project}: project name
  • %i or {project_id}: project UUID
  • %c or {url}: server URL (http://user:password@server:port)
")) diff --git a/gns3/ui/general_preferences_page.ui b/gns3/ui/general_preferences_page.ui index f1a9799a4..f5ec5ab69 100755 --- a/gns3/ui/general_preferences_page.ui +++ b/gns3/ui/general_preferences_page.ui @@ -418,7 +418,7 @@
- <html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d = title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i = project UUID</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n = node UUID</li></ul><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c = server URL</li></ul></body></html> + <html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h or {host} = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p or {port} = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d or {name} = title of the console (node name)</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P or {project} = project</li></ul><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i or {project_id} = project UUID</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n or {node_id} = node UUID</li></ul><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c or {url} = server URL</li></ul></body></html> true @@ -528,7 +528,7 @@ - <html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P = VNC display</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d = title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i = project UUID</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n = node UUID</li></ul></body></html> + <html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h or {host} = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p or {port} = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P or {display} = VNC display</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d or {name} = node name</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%T or {project} = project name</li></ul><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i or {project_id} = project UUID</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n or {node_id} = node UUID</li></ul><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c or {url} = server URL</li></ul></body></html> true @@ -597,7 +597,7 @@ - <html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d = title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i = project UUID</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n = node UUID</li></ul><p><br/></p></body></html> + <html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h or {host} = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p or {port} = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d or {name} = node name</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P or {project} = project name</li></ul><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i or {project_id} = project UUID</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n or {node_id} = node UUID</li></ul><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c or {url} = server URL</li></ul></body></html> true diff --git a/gns3/ui/general_preferences_page_ui.py b/gns3/ui/general_preferences_page_ui.py index 6f2c51b50..fc3bd1a0b 100644 --- a/gns3/ui/general_preferences_page_ui.py +++ b/gns3/ui/general_preferences_page_ui.py @@ -558,7 +558,7 @@ def retranslateUi(self, GeneralPreferencesPageWidget): self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiImagesTab), _translate("GeneralPreferencesPageWidget", "Binary images")) self.uiTelnetConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Console settings")) self.uiTelnetConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for Telnet:")) - self.uiTelnetConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "

Command line replacements:

  • %h = console IP or hostname
  • %p = console port
  • %d = title of the console
  • %i = project UUID
    • %n = node UUID
  • %c = server URL
")) + self.uiTelnetConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "

Command line replacements:

  • %h or {host} = console IP or hostname
  • %p or {port} = console port
  • %d or {name} = title of the console (node name)
    • %P or {project} = project
  • %i or {project_id} = project UUID
    • %n or {node_id} = node UUID
  • %c or {url} = server URL
")) self.uiTelnetConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit")) self.uiConsoleMiscGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Miscellaneous")) self.uiDelayConsoleAllSpinBox.setSuffix(_translate("GeneralPreferencesPageWidget", " ms")) @@ -566,12 +566,12 @@ def retranslateUi(self, GeneralPreferencesPageWidget): self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiConsoleTab), _translate("GeneralPreferencesPageWidget", "Console applications")) self.uiVNCConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Settings for VNC connections")) self.uiVNCConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for VNC:")) - self.uiVNCConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "

Command line replacements:

  • %h = console IP or hostname
  • %p = console port
  • %P = VNC display
  • %d = title of the console
  • %i = project UUID
  • %n = node UUID
")) + self.uiVNCConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "

Command line replacements:

  • %h or {host} = console IP or hostname
  • %p or {port} = console port
  • %P or {display} = VNC display
  • %d or {name} = node name
    • %T or {project} = project name
  • %i or {project_id} = project UUID
    • %n or {node_id} = node UUID
  • %c or {url} = server URL
")) self.uiVNCConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit")) self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiVNCTab), _translate("GeneralPreferencesPageWidget", "VNC")) self.uiSPICEConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Settings for SPICE connections")) self.uiSPICEConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for SPICE:")) - self.uiSPICEConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "

Command line replacements:

  • %h = console IP or hostname
  • %p = console port
  • %d = title of the console
  • %i = project UUID
  • %n = node UUID


")) + self.uiSPICEConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "

Command line replacements:

  • %h or {host} = console IP or hostname
  • %p or {port} = console port
  • %d or {name} = node name
    • %P or {project} = project name
  • %i or {project_id} = project UUID
    • %n or {node_id} = node UUID
  • %c or {url} = server URL
")) self.uiSPICEConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit")) self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiSPICETab), _translate("GeneralPreferencesPageWidget", "SPICE")) self.uiSceneWidthLabel.setText(_translate("GeneralPreferencesPageWidget", "Default width:")) diff --git a/gns3/ui/packet_capture_preferences_page.ui b/gns3/ui/packet_capture_preferences_page.ui index 0b145aed5..c2eaceea2 100755 --- a/gns3/ui/packet_capture_preferences_page.ui +++ b/gns3/ui/packet_capture_preferences_page.ui @@ -79,7 +79,7 @@ - <html><head/><body><p>Command line replacements:</p><p>%c = capture file (PCAP format)</p></body></html> + <html><head/><body><p>Command line replacements:</p><p>%c or {pcap_file} = capture file (PCAP format)</p><p>%P or {project} = project name</p><p>%d or {link_description} = link description</p></body></html> diff --git a/gns3/ui/packet_capture_preferences_page_ui.py b/gns3/ui/packet_capture_preferences_page_ui.py index b2cb98049..dfc910891 100644 --- a/gns3/ui/packet_capture_preferences_page_ui.py +++ b/gns3/ui/packet_capture_preferences_page_ui.py @@ -2,12 +2,15 @@ # Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/packet_capture_preferences_page.ui' # -# Created by: PyQt5 UI code generator 5.9 +# Created by: PyQt5 UI code generator 5.15.6 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + from PyQt5 import QtCore, QtGui, QtWidgets + class Ui_PacketCapturePreferencesPageWidget(object): def setupUi(self, PacketCapturePreferencesPageWidget): PacketCapturePreferencesPageWidget.setObjectName("PacketCapturePreferencesPageWidget") @@ -64,6 +67,11 @@ def setupUi(self, PacketCapturePreferencesPageWidget): self.retranslateUi(PacketCapturePreferencesPageWidget) QtCore.QMetaObject.connectSlotsByName(PacketCapturePreferencesPageWidget) + PacketCapturePreferencesPageWidget.setTabOrder(self.uiPreconfiguredCaptureReaderCommandComboBox, self.uiPreconfiguredCaptureReaderCommandPushButton) + PacketCapturePreferencesPageWidget.setTabOrder(self.uiPreconfiguredCaptureReaderCommandPushButton, self.uiCaptureReaderCommandLineEdit) + PacketCapturePreferencesPageWidget.setTabOrder(self.uiCaptureReaderCommandLineEdit, self.uiAutoStartCheckBox) + PacketCapturePreferencesPageWidget.setTabOrder(self.uiAutoStartCheckBox, self.uiCaptureAnalyzerCommandLineEdit) + PacketCapturePreferencesPageWidget.setTabOrder(self.uiCaptureAnalyzerCommandLineEdit, self.uiRestoreDefaultsPushButton) def retranslateUi(self, PacketCapturePreferencesPageWidget): _translate = QtCore.QCoreApplication.translate @@ -74,6 +82,5 @@ def retranslateUi(self, PacketCapturePreferencesPageWidget): self.uiCaptureReaderCommandLabel.setText(_translate("PacketCapturePreferencesPageWidget", "Packet capture reader command:")) self.uiAutoStartCheckBox.setText(_translate("PacketCapturePreferencesPageWidget", "Automatically start the packet capture application")) self.uiCaptureAnalyzerCommandLabel.setText(_translate("PacketCapturePreferencesPageWidget", "Packet capture analyzer command:")) - self.uiCaptureReaderCommandLineEdit.setToolTip(_translate("PacketCapturePreferencesPageWidget", "

Command line replacements:

%c = capture file (PCAP format)

")) + self.uiCaptureReaderCommandLineEdit.setToolTip(_translate("PacketCapturePreferencesPageWidget", "

Command line replacements:

%c or {pcap_file} = capture file (PCAP format)

%P or {project} = project name

%d or {link_description} = link description

")) self.uiRestoreDefaultsPushButton.setText(_translate("PacketCapturePreferencesPageWidget", "Restore defaults")) - diff --git a/gns3/version.py b/gns3/version.py index 56fc56cd3..8454f031f 100644 --- a/gns3/version.py +++ b/gns3/version.py @@ -23,9 +23,8 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.2.44.dev1" - -__version_info__ = (2, 2, 44, 99) +__version__ = "2.2.44" +__version_info__ = (2, 2, 44, 0) if "dev" in __version__: try: diff --git a/gns3/vnc_console.py b/gns3/vnc_console.py index 928b9bf1b..75c812443 100644 --- a/gns3/vnc_console.py +++ b/gns3/vnc_console.py @@ -48,16 +48,27 @@ def vncConsole(node, port, command): # replace the place-holders by the actual values command = command.replace("%h", host) command = command.replace("%p", str(port)) - command = command.replace("%P", str(port - 5900)) + command = command.replace("%D", str(port - 5900)) command = command.replace("%d", name.replace('"', '\\"')) + command = command.replace("%P", node.project().name().replace('"', '\\"')) command = command.replace("%i", node.project().id()) command = command.replace("%n", str(node.id())) + command = command.replace("%c", Controller.instance().httpClient().fullUrl()) + + command = command.replace("{host}", host) + command = command.replace("{port}", str(port)) + command = command.replace("{display}", str(port - 5900)) + command = command.replace("{name}", name.replace('"', '\\"')) + command = command.replace("{project}", node.project().name().replace('"', '\\"')) + command = command.replace("{project_id}", node.project().id()) + command = command.replace("{node_id}", str(node.id())) + command = command.replace("{url}", Controller.instance().httpClient().fullUrl()) try: log.debug('starting VNC program "{}"'.format(command)) if sys.platform.startswith("win"): # use the string on Windows - subprocess.Popen(command) + subprocess.Popen(command, env=os.environ) else: # use arguments on other platforms args = shlex.split(command) diff --git a/requirements.txt b/requirements.txt index 5f5f1e58a..c9cd5f20c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ jsonschema>=4.17.3,<4.18; python_version >= '3.7' # v4.17.3 is the last version to support Python 3.7 jsonschema==3.2.0; python_version < '3.7' # v3.2.0 is the last version to support Python 3.6 -sentry-sdk==1.32.0,<1.33 +sentry-sdk==1.34.0,<1.35 psutil==5.9.6 distro>=1.8.0 truststore>=0.8.0; python_version >= '3.10' diff --git a/tests/conftest.py b/tests/conftest.py index 0b2c28f11..12b2a1096 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -75,6 +75,7 @@ def controller(): Controller._instance = None c = Controller.instance() c._http_client = MagicMock() + c._http_client.fullUrl.return_value = "http://localhost:3080" return c diff --git a/tests/test_local_server.py b/tests/test_local_server.py index d308e424a..187726040 100644 --- a/tests/test_local_server.py +++ b/tests/test_local_server.py @@ -16,7 +16,6 @@ # along with this program. If not, see . import sys -import json import pytest import logging import subprocess @@ -87,7 +86,7 @@ def test_startLocalServer(tmpdir, local_server, local_server_path): '--debug', '--log=' + str(tmpdir / "gns3_server.log"), '--pid=' + str(tmpdir / "gns3_server.pid") - ], stderr=unittest.mock.ANY) + ], stderr=unittest.mock.ANY, env=unittest.mock.ANY) def test_killAlreadyRunningServer(local_server): diff --git a/tests/test_spice_console.py b/tests/test_spice_console.py index 7f35dd869..792d852b7 100644 --- a/tests/test_spice_console.py +++ b/tests/test_spice_console.py @@ -17,28 +17,30 @@ import os import shlex -import pytest from unittest.mock import patch from gns3.spice_console import spiceConsole def test_spice_console_on_linux_and_mac(vpcs_device): + with patch('subprocess.Popen') as popen, \ patch('sys.platform', new="linux"): - vpcs_device.settings()["console_host"] = "localhost" spiceConsole(vpcs_device, '2525', 'command %h %p') - popen.assert_called_once_with(shlex.split('command localhost 2525'), env=os.environ) - + popen.assert_called_with(shlex.split('command localhost 2525'), env=os.environ) + spiceConsole(vpcs_device, '2525', 'command {host} {port}') + popen.assert_called_with(shlex.split('command localhost 2525'), env=os.environ) def test_spice_console_on_windows(vpcs_device): - with patch('subprocess.Popen') as popen, \ + + with patch('subprocess.Popen') as p, \ patch('sys.platform', new="win"): vpcs_device.settings()["console_host"] = "localhost" spiceConsole(vpcs_device, '2525', 'command %h %p') - popen.assert_called_once_with('command localhost 2525') - + p.assert_called_with('command localhost 2525', env=os.environ) + spiceConsole(vpcs_device, '2525', 'command {host} {port}') + p.assert_called_with('command localhost 2525', env=os.environ) # def test_spice_console_on_linux_with_popen_issues(): # with patch('subprocess.Popen', side_effect=OSError("Dummy")), \ @@ -49,9 +51,11 @@ def test_spice_console_on_windows(vpcs_device): def test_spice_console_with_ipv6_support(vpcs_device): + with patch('subprocess.Popen') as popen, \ patch('sys.platform', new="linux"): - vpcs_device.settings()["console_host"] = "::1" spiceConsole(vpcs_device, '2525', 'command %h %p') - popen.assert_called_once_with(shlex.split('command [::1] 2525'), env=os.environ) + popen.assert_called_with(shlex.split('command [::1] 2525'), env=os.environ) + spiceConsole(vpcs_device, '2525', 'command {host} {port}') + popen.assert_called_with(shlex.split('command [::1] 2525'), env=os.environ) diff --git a/tests/test_vnc_console.py b/tests/test_vnc_console.py index c0e71515e..b963867bb 100644 --- a/tests/test_vnc_console.py +++ b/tests/test_vnc_console.py @@ -17,31 +17,36 @@ import os import shlex -import pytest from unittest.mock import patch from gns3.vnc_console import vncConsole - def test_vnc_console_on_linux_and_mac(vpcs_device): - with patch('subprocess.Popen') as popen, \ + + with patch('subprocess.Popen') as p, \ patch('sys.platform', new="linux"): vpcs_device.settings()["console_host"] = "localhost" - vncConsole(vpcs_device, 6000, 'command %h %p %P') - popen.assert_called_once_with(shlex.split('command localhost 6000 100'), env=os.environ) + vncConsole(vpcs_device, 6000, 'command %h %p %D') + p.assert_called_with(shlex.split('command localhost 6000 100'), env=os.environ) + vncConsole(vpcs_device, 6000, 'command {host} {port} {display}') + p.assert_called_with(shlex.split('command localhost 6000 100'), env=os.environ) def test_vnc_console_on_windows(vpcs_device): - with patch('subprocess.Popen') as popen, \ + + with patch('subprocess.Popen') as p, \ patch('sys.platform', new="win"): vpcs_device.settings()["console_host"] = "localhost" - vncConsole(vpcs_device, 6000, 'command %h %p %P') - popen.assert_called_once_with('command localhost 6000 100') + vncConsole(vpcs_device, 6000, 'command %h %p %D') + p.assert_called_with('command localhost 6000 100', env=os.environ) + vncConsole(vpcs_device, 6000, 'command {host} {port} {display}') + p.assert_called_with('command localhost 6000 100', env=os.environ) -# def test_vnc_console_on_linux_with_popen_issues(): -# with patch('subprocess.Popen', side_effect=OSError("Dummy")), \ +# def test_vnc_console_on_linux_with_popen_issues(vpcs_device): +# with patch('subprocess.Popen', side_effect=subprocess.SubprocessError()), \ # patch('sys.platform', new="linux"): +# vpcs_device.settings()["console_host"] = "localhost" # -# with pytest.raises(OSError): -# vncConsole('localhost', 6000, 'command %h %p %P') +# with pytest.raises(subprocess.SubprocessError): +# vncConsole(vpcs_device, 6000, 'command %h %p %P')