diff --git a/CHANGES.md b/CHANGES.md index 5dc7b06..cd533fe 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ * Improve handling of environment file specification (#63) * Stop running container on SIGINT (#62) +* `xcetool image run --server` prints server and viewer urls (#46) ## Changes in 0.1.1 diff --git a/docs/xcetool.md b/docs/xcetool.md index 58f7597..dae8e87 100644 --- a/docs/xcetool.md +++ b/docs/xcetool.md @@ -19,11 +19,19 @@ a CWL file defining a corresponding application package. This subcommand runs an xcengine container image. An image can also be run using the `docker run` command, but `xcetool image run` provides some additional convenience -(e.g. easy configuration of the HTTP port). - -If you give the `--server` flag, `xcetool` will run the container indefinitely as an -xcube server. You can stop the container and force `xcetool` to exit by pressing -ctrl-C on the command line (or by sending it an interrupt signal in some other way). +(e.g. easy configuration of a server HTTP port). + +If you use the `--server` option with `xcetool image run`, the image will be run in +xcube server mode: after the code from the input notebook is used to generate datasets, +those datasets will be made available in an xcube server instance. You can also use +the `--port` option to select the HTTP port where the xcube server should be exposed. +The server also includes an interactive web viewer component. On start-up, `xcetool` +will print the URLs of the xcube server and viewer to the standard output. + +If you give the `--server` or `--port` options, `xcetool` will run the container +indefinitely as an xcube server and viewer instance. You can stop the container and +force `xcetool` to exit by pressing ctrl-C on the command line (or by sending it an +interrupt signal in some other way). ### `xcetool make-script` diff --git a/test/test_cli.py b/test/test_cli.py index eb6d5c7..a48496d 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -1,3 +1,4 @@ +import re import runpy import subprocess from unittest.mock import patch, ANY, MagicMock @@ -102,3 +103,27 @@ def test_image_run(runner_mock): from_saved=False, keep=False, ) + + +@patch("xcengine.cli.ContainerRunner") +def test_image_run_print_urls(runner_mock): + cli_runner = CliRunner() + instance_mock = runner_mock.return_value = MagicMock() + port = 32168 + result = cli_runner.invoke( + cli, ["image", "run", "--server", "--port", str(port), "foo"] + ) + runner_mock.assert_called_once_with(image="foo", output_dir=None) + assert result.exit_code == 0 + instance_mock.run.assert_called_once_with( + run_batch=False, + host_port=port, + from_saved=False, + keep=False, + ) + assert re.search( + f"server.*http://localhost:{port}", result.stdout, re.IGNORECASE + ) + assert re.search( + f"viewer.*http://localhost:{port}/viewer", result.stdout, re.IGNORECASE + ) diff --git a/xcengine/cli.py b/xcengine/cli.py index 58c940d..cfb7f9a 100644 --- a/xcengine/cli.py +++ b/xcengine/cli.py @@ -8,6 +8,7 @@ import os import pathlib import subprocess +import sys import tempfile import click @@ -18,6 +19,7 @@ LOGGER = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) + @click.group( help="Create and run compute engine scripts and containers " "from IPython notebooks" @@ -154,9 +156,11 @@ def build( ) image = image_builder.build() if eoap: + class IndentDumper(yaml.Dumper): def increase_indent(self, flow=False, indentless=False): return super(IndentDumper, self).increase_indent(flow, False) + eoap.write_text( yaml.dump( image_builder.create_cwl(), @@ -221,6 +225,14 @@ def run( is not click.core.ParameterSource.DEFAULT ) actual_port = port if server or port_specified_explicitly else None + if actual_port is not None: + print( + f"xcube server will be available at http://localhost:{actual_port}" + ) + print( + f"xcube viewer will be available at " + f"http://localhost:{actual_port}/viewer" + ) runner.run( run_batch=batch, host_port=actual_port,