From e1a61905e13829b66bb71e270aa34a1a1d8b32db Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Mon, 22 Aug 2022 17:28:04 -0400 Subject: [PATCH] Update the docs for the "view" command --- docs/cli/view.rst | 67 +++++++++++++++++++++++++++++++++++++++++++++++ toasty/cli.py | 18 ++++++++----- 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/docs/cli/view.rst b/docs/cli/view.rst index 3d9b37f..114d9f6 100644 --- a/docs/cli/view.rst +++ b/docs/cli/view.rst @@ -26,17 +26,27 @@ Detailed Usage .. code-block:: shell toasty view + [--tunnel HOST, -t HOST] [--appurl URL] [--blankval NUMBER] [--browser BROWSER, -b BROWSER] [--hdu-index INDEX[,INDEX,...]] [--parallelism COUNT, -j COUNT] + [--tile-only] {FITS [FITS ...]} The ``FITS`` argument(s) give the path(s) of one or more input FITS files. These will be automatically tiled if necessary, then made available on a local web server so that the WWT viewer can access the data. +The ``-t HOST`` or ``--tunnel HOST`` option can be used to view an image stored +on the remote machine named ``HOST``, using `SSH`_. In order for this work, SSH +`connection sharing`_ must be enabled, and Toasty must be installed on the +destination machine. See more in :ref:`cli-view-tunneled` below. + +.. _SSH: https://en.wikipedia.org/wiki/Secure_Shell +.. _connection sharing: https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing + The ``-b`` or ``--browser`` option specifies which web browser to use, using an identifier as understood by the `Python "webbrowser" module`_. Typical choices might be ``firefox``, ``safari``, or ``google-chrome``. If unspecified, a @@ -61,6 +71,9 @@ The ``--appurl`` option can be used to override the base URL for the preview app that will be used. This can be helpful when developing new features in one of these apps. +If the ``--tile-only`` option is specified, the data are tiled but no web +browser is launched. This can be useful when automating Toasty workflows. + Details ======= @@ -83,6 +96,60 @@ be used. Otherwise, Toasty will reproject the input data into a tangential +.. _cli-view-tunneled: + +Tunneled Image Viewing +====================== + +The “tunneled” mode of this command allows you to view images that live on +another machine. + +The basic usage of this mode is + + +.. code-block:: shell + + toasty view -t HOST FITS1 [FITS2...] + +where ``HOST`` is the hostname of the machine with the image(s), and the +``FITSn`` values are the paths of the images on the machine relative to the +destination user's home directory. Or, absolute paths are also OK. + +Here, ``HOST`` is any hostname that will be accepted by your ``ssh`` program. +This means that it can be a “virtual” host alias set up in your ``.ssh/config`` +file, for instance. + +In order for this functionality to work, it is necessary that the SSH commands +will not need to prompt you interactively in order to log in. This requires that +either you have key-based SSH authentication set up, with passphrase-less keys +or a key agent running, *or* that SSH connection reuse is activated for the +target host, and you have an existing SSH connection to the host open. The +program `stund`_ can be helpful for setting up long-lived connections to avoid +password prompts. + +.. _stund: https://github.com/pkgw/stund + +The target host must also have Toasty installed, such that if you log in to a +terminal over SSH, the command ``toasty`` is available. + +In tunneled mode, the following sequence of events happens: + +1. SSH is used to run a ``toasty view`` command on the target host to tile the + requested data sets. Relevant flags such as ``-j`` / ``--parallelism`` are + forwarded to the remote host. +2. SSH is used to run a ``wwtdatatool serve`` command on the target host, + starting an HTTP-based data server. +3. A local SSH port forward is created so that the HTTP server can be accessed + from the local machine. +4. A local web browser is launched with the proper setup to view the data via + the port forward. +5. When the local command is stopped, the remote HTTP server is shut down, and + the port forward is cancelled. + +The remote HTTP server is set up in a way where it should shut down +automatically if the SSH connection is dropped for any reason. + + See Also ======== diff --git a/toasty/cli.py b/toasty/cli.py index 9f3a678..0d2ab3a 100644 --- a/toasty/cli.py +++ b/toasty/cli.py @@ -866,7 +866,7 @@ def view_getparser(parser): "--tunnel", "-t", metavar="HOST", - help="Use SSH tunnels to view an image stored on a remote host", + help="Use SSH tunneling to view an image stored on a remote host", ) parser.add_argument( "--browser", @@ -936,11 +936,13 @@ def view_tunneled(settings): # that by avoiding $command and writing an `exec` to stdin. This is gross # and raises issues of escaping funky filenames, but those issues already # exist with SSH command arguments. + # + # We give SSH `-T` to prevent warnings about not allocating pseudo-TTYs. ssh_argv = ["ssh", "-T", settings.tunnel] toasty_argv = ["exec", "toasty", "view", "--tile-only"] if settings.parallelism: - toasty_argv += ["--parallelism", int(settings.parallelism)] + toasty_argv += ["--parallelism", str(settings.parallelism)] toasty_argv += settings.paths print(f"Preparing data on `{settings.tunnel}` ...\n") @@ -949,9 +951,9 @@ def view_tunneled(settings): ssh_argv, shell=False, close_fds=True, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - stdin=subprocess.PIPE, text=True, ) @@ -977,7 +979,8 @@ def view_tunneled(settings): # Next, launch the server. Same environment workaround as before. We use a # special "heartbeat" mode in the server to get it to exit reliably when the - # SSH connection goes away. + # SSH connection goes away. `--port 0` has the OS automatically choose a + # free port. serve_argv = [ "exec", @@ -1056,9 +1059,10 @@ def view_tunneled(settings): print(f" Local port: {port}") - # Somewhat annoyingly, for the research app we currently need to get the URL - # of the imageset. The most reliable way to do that is going to be to look - # at the WTML. + # Somewhat annoyingly, for the research app we currently need to get + # the URL of the imageset. The most reliable way to do that is going + # to be to look at the WTML. This reproduces some of the logic in + # `wwt_data_formats.server.preview_wtml()`. wtml_base = os.path.basename(index_rel_path).replace("_rel.wtml", ".wtml") local_wtml_url = urlunparse(