diff --git a/src/components/vm/consoles/desktopConsole.jsx b/src/components/vm/consoles/desktopConsole.jsx index 454551953..bad4a68d8 100644 --- a/src/components/vm/consoles/desktopConsole.jsx +++ b/src/components/vm/consoles/desktopConsole.jsx @@ -17,9 +17,12 @@ * along with Cockpit; If not, see . */ import React from "react"; +import { CodeBlock, CodeBlockCode } from "@patternfly/react-core/dist/esm/components/CodeBlock"; import { DesktopViewer } from '@patternfly/react-console'; +import { getServerAddress, needsTunnel } from "./utils.js"; import cockpit from "cockpit"; +import store from './../../../store.js'; const _ = cockpit.gettext; @@ -37,6 +40,11 @@ function fmt_to_fragments(fmt) { } const DesktopConsoleDownload = ({ vnc, spice, onDesktopConsole }) => { + // DesktopViewer prefers spice over vnc + const address = (spice && spice.address) || (vnc && vnc.address); + const serverAddress = getServerAddress(); + const loggedUser = store.getState().systemInfo.loggedUser; + return ( {

{fmt_to_fragments(_("Clicking \"Launch remote viewer\" will download a .vv file and launch $0."), Remote Viewer)}

+ {needsTunnel(address, serverAddress) &&

+ {_("SSH tunnel needs to be set up on client:")} + + {`ssh -L 5900:localhost:5900 -N ${loggedUser.name}@${serverAddress}`} + +

}

{fmt_to_fragments(_("$0 is available for most operating systems. To install it, search for it in GNOME Software or run the following:"), Remote Viewer)}

diff --git a/src/components/vm/consoles/utils.js b/src/components/vm/consoles/utils.js new file mode 100644 index 000000000..dbc46b07c --- /dev/null +++ b/src/components/vm/consoles/utils.js @@ -0,0 +1,43 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ +export function getServerAddress() { + return window.location.hostname; +} + +export function isLocalhost(address) { + return address === "localhost" || address.startsWith("127"); +} + +export function isAmbigious(address) { + return isLocalhost(address) || ["0", "0.0.0.0"].includes(address); +} + +// Get address where VNC or SPICE server is located +export function getConsoleAddress(consoleDetails) { + let address = consoleDetails.address; + + if (!address || isAmbigious(address)) + address = getServerAddress(); + + return address; +} + +export function needsTunnel(consoleAddress, serverAddress) { + return isLocalhost(consoleAddress) && !isLocalhost(serverAddress); +} diff --git a/test/check-machines-consoles b/test/check-machines-consoles index f85ddbc24..e7e157972 100755 --- a/test/check-machines-consoles +++ b/test/check-machines-consoles @@ -67,6 +67,8 @@ class TestMachinesConsoles(VirtualMachinesCase): b.wait_in_text('.pf-c-expandable-section__content', 'Clicking "Launch remote viewer" will download') + b.wait_not_in_text('.pf-c-expandable-section__content', 'SSH tunnel needs to be set up on client') + b.assert_pixels("#vm-subVmTest1-consoles-page", "vm-details-console-external", skip_layouts=["rtl"]) def testInlineConsole(self, urlroot=""):